ViewController.swift 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354
  1. //
  2. // ViewController.swift
  3. // TestQmeraLite
  4. //
  5. // Created by Qindi on 29/11/21.
  6. //
  7. import UIKit
  8. import NexilisLite
  9. import AVKit
  10. import AVFoundation
  11. import SwiftUI
  12. import Speech
  13. import Alamofire
  14. import WebKit
  15. class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMABDelegate, WKNavigationDelegate {
  16. let playerController = AVPlayerViewController()
  17. static var sURL = "https://www.google.com"
  18. static var tab3 = "0"
  19. public var isShow: Bool = false
  20. public static var chatButton = UIButton()
  21. public static var callButton = UIButton()
  22. public static var ccButton = UIButton()
  23. public static var streamingButton = UIButton()
  24. public static var postButton = UIButton()
  25. public static var middleButton = UIButton()
  26. var buttonChatGR : UITapGestureRecognizer?
  27. var buttonCallGR : UITapGestureRecognizer?
  28. var buttonCCGR : UITapGestureRecognizer?
  29. var buttonStreamGR : UITapGestureRecognizer?
  30. var floating : FloatingButton?
  31. var firstTab : FirstTabViewController?
  32. var secondTab : SecondTabViewController?
  33. var thirdTab : ThirdTabViewController?
  34. var fourthTab : FourthTabViewController?
  35. let emptyTab = EmptyTabViewController()
  36. public static var isTab1 = true
  37. public static var isTab2 = false
  38. public static var isTab3 = false
  39. public static var isTab4 = false
  40. public static var isExpandButton = false
  41. public static var alwaysHideButton = false
  42. static var listPullFB: [String] = []
  43. static var datePullFB: Date?
  44. let welcomeVC = UIViewController()
  45. let privacyPolicyVC = UIViewController()
  46. var termVC: UIViewController?
  47. let welcomeDesc = UILabel()
  48. let termText = "Read our Terms of Service. Tap \"Agree and Continue\" to accept Terms of Service.".localized()
  49. let term = "Terms of Service.".localized()
  50. var firstLoad = true
  51. let privacyWV = WKWebView()
  52. let indicatorCounterFB = UIView()
  53. let labelCounterFB = UILabel()
  54. public static var def: ViewController?
  55. override func viewDidLoad() {
  56. super.viewDidLoad()
  57. DispatchQueue.main.async { [self] in
  58. if let response = Nexilis.writeSync(message: getPrefs(key: ""), timeout: 5000) {
  59. if response.mBodies[CoreMessage_TMessageKey.ERRCOD] == "00" {
  60. let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
  61. if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [[String: Any?]] {
  62. UserDefaults.standard.removeObject(forKey: "app_builder_url_first_tab")
  63. UserDefaults.standard.removeObject(forKey: "app_builder_url_third_tab")
  64. UserDefaults.standard.removeObject(forKey: "app_builder_custom_tab")
  65. UserDefaults.standard.removeObject(forKey: "app_builder_url_base")
  66. UserDefaults.standard.removeObject(forKey: "app_builder_url_qms")
  67. UserDefaults.standard.removeObject(forKey: "app_builder_icon_dock")
  68. UserDefaults.standard.removeObject(forKey: "app_builder_icon_ss")
  69. UserDefaults.standard.removeObject(forKey: "app_builder_background")
  70. UserDefaults.standard.removeObject(forKey: "app_builder_compressor")
  71. for j in json {
  72. if let firstTab = j["app_builder_url_first_tab"] as? String {
  73. PrefsUtil.setURLFirstTab(value: firstTab)
  74. ViewController.sURL = firstTab
  75. }
  76. if let thirdTab = j["app_builder_url_third_tab"] as? String {
  77. PrefsUtil.setURLThirdTab(value: thirdTab)
  78. ViewController.tab3 = thirdTab
  79. }
  80. if let customTab = j["app_builder_custom_tab"] as? String {
  81. PrefsUtil.setCustomTab(cust: customTab)
  82. }
  83. if let urlBase = j["app_builder_url_base"] as? String {
  84. PrefsUtil.setURLBase(value: urlBase)
  85. }
  86. if let urlQMS = j["app_builder_url_qms"] as? String {
  87. PrefsUtil.setURLQMS(value: urlQMS)
  88. }
  89. if let iconDock = j["app_builder_icon_dock"] as? String {
  90. PrefsUtil.setIconDock(value: iconDock)
  91. }
  92. if let iconSS = j["app_builder_icon_ss"] as? String {
  93. PrefsUtil.setIconSS(value: iconSS)
  94. }
  95. if let background = j["app_builder_background"] as? String {
  96. PrefsUtil.setBackground(value: background)
  97. }
  98. if let url_privacy_policy = j["app_builder_url_privacy_policy"] as? String {
  99. PrefsUtil.setURLPrivacyPolicy(value: url_privacy_policy)
  100. }
  101. if let enable_privacy_policy = j["app_builder_enable_privacy_policy"] as? String {
  102. PrefsUtil.setEnablePrivacyPolicy(value: enable_privacy_policy == "1" ? true : false)
  103. }
  104. }
  105. startView()
  106. }
  107. } else {
  108. startView()
  109. }
  110. } else {
  111. startView()
  112. }
  113. }
  114. }
  115. func startView() {
  116. let topBorder = CALayer()
  117. topBorder.backgroundColor = UIColor.gray.withAlphaComponent(0.5).cgColor
  118. topBorder.frame = CGRect(x: 0, y: 0, width: tabBar.frame.size.width, height: 1)
  119. tabBar.layer.addSublayer(topBorder)
  120. ViewController.def = self
  121. title = Bundle.main.displayName
  122. let customTab = PrefsUtil.getCustomTab().split(separator: ",")
  123. let cpaasMode = PrefsUtil.getCpaasMode()
  124. var tabs : [UIViewController] = []
  125. firstTab = storyboard?.instantiateViewController(withIdentifier: "firstTabVC") as? FirstTabViewController
  126. secondTab = storyboard?.instantiateViewController(withIdentifier: "secondTabVC") as? SecondTabViewController
  127. thirdTab = storyboard?.instantiateViewController(withIdentifier: "thirdTabVC") as? ThirdTabViewController
  128. fourthTab = storyboard?.instantiateViewController(withIdentifier: "fourthTabVC") as? FourthTabViewController
  129. self.delegate = self
  130. firstTab?.tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(named: "tab_1_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(named: "tab_1_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal).withTintColor(.mainColor))
  131. secondTab?.tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(named: "tab_2_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(named: "tab_2_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal).withTintColor(.mainColor))
  132. thirdTab?.tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(named: "tab_3_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(named: "tab_3_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal).withTintColor(.mainColor))
  133. fourthTab?.tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(named: "tab_4_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(named: "tab_4_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal).withTintColor(.mainColor))
  134. var i = 0
  135. var j = 0
  136. while j < customTab.count {
  137. if(((i == 1 && customTab.count == 3) || i == 2) &&
  138. (cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)){
  139. tabs.append(emptyTab)
  140. }
  141. else {
  142. switch(customTab[j]){
  143. case "1":
  144. tabs.append(firstTab!)
  145. case "2":
  146. tabs.append(secondTab!)
  147. case "3":
  148. tabs.append(thirdTab!)
  149. case "4":
  150. tabs.append(fourthTab!)
  151. default:
  152. break
  153. }
  154. j += 1
  155. }
  156. i += 1
  157. }
  158. if(cpaasMode == PrefsUtil.CPAAS_MODE_BURGER){
  159. navigationController?.setNavigationBarHidden(false, animated: false)
  160. //print("cpaas mode burger")
  161. let childrenMenu : [UIAction] = [
  162. UIAction(title: "Contact Center", handler: {[weak self](_) in
  163. self?.ccTap()
  164. }),
  165. UIAction(title: "Chat", handler: {[weak self](_) in
  166. self?.chatTap()
  167. }),
  168. UIAction(title: "Call", handler: {[weak self](_) in
  169. self?.callTap()
  170. }),
  171. UIAction(title: "New Post", handler: {[weak self](_) in
  172. self?.postTap()
  173. }),
  174. UIAction(title: "Live Streaming", handler: {[weak self](_) in
  175. self?.streamTap()
  176. }),
  177. // UIAction(title: "Settings", handler: {[weak self](_) in
  178. // self?.settingTap()
  179. // }),
  180. ]
  181. let menu = UIMenu(title: "", children: childrenMenu)
  182. if PrefsUtil.getIconDock() != nil {
  183. DispatchQueue.global().async {
  184. ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getUrlDock()!)!) { data, response, error in
  185. guard let data = data, error == nil else { return }
  186. // always update the UI from the main thread
  187. DispatchQueue.main.async() { [self] in
  188. navigationItem.rightBarButtonItem = UIBarButtonItem(image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), primaryAction: .none, menu: menu)
  189. }
  190. }
  191. }
  192. } else {
  193. navigationItem.rightBarButtonItem = UIBarButtonItem(image: resizeImage(image: UIImage(named: "pb_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), primaryAction: .none, menu: menu)
  194. }
  195. }
  196. if((cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)){
  197. createMidFloatingButton()
  198. navigationController?.setNavigationBarHidden(true, animated: false)
  199. ViewController.pullActionButton()
  200. }
  201. // if((cpaasMode == PrefsUtil.CPAAS_MODE_FLOATING || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)) {
  202. // let rect = CGRect(x: self.view.bounds.width - 100, y: self.view.bounds.height / 2, width: 50, height: 250)
  203. // floating = FloatingButton()
  204. // floating?.frame = rect
  205. // floating?.isShow = true
  206. //
  207. // view.addSubview(floating!)
  208. // navigationController?.setNavigationBarHidden(true, animated: false)
  209. // }
  210. self.setViewControllers(tabs, animated: false)
  211. if(cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX){
  212. if(customTab.count == 3){
  213. self.tabBar.items?[1].isEnabled = false
  214. }
  215. self.tabBar.items?[2].isEnabled = false
  216. }
  217. let center: NotificationCenter = NotificationCenter.default
  218. center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
  219. center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil)
  220. checkCounter()
  221. willappear()
  222. }
  223. static func getiPhoneModel() -> String {
  224. var systemInfo = utsname()
  225. uname(&systemInfo)
  226. let machineMirror = Mirror(reflecting: systemInfo.machine)
  227. let identifier = machineMirror.children.reduce("") { identifier, element in
  228. guard let value = element.value as? Int8, value != 0 else { return identifier }
  229. return identifier + String(UnicodeScalar(UInt8(value)))
  230. }
  231. var model = ""
  232. if let modelName = mapToDevice(identifier: identifier) {
  233. model = modelName
  234. } else {
  235. model = "Unknown"
  236. }
  237. return model
  238. }
  239. static func mapToDevice(identifier: String) -> String? {
  240. // Add mappings for iPhone models as needed
  241. switch identifier {
  242. case "iPhone1,1", "iPhone1,2", "iPhone2,1", "iPhone3,1", "iPhone3,2", "iPhone3,3", "iPhone4,1", "iPhone5,1", "iPhone5,2", "iPhone5,3", "iPhone5,4", "iPhone6,1", "iPhone6,2", "iPhone7,1", "iPhone7,2", "iPhone8,1", "iPhone8,2", "iPhone8,4", "iPhone9,1", "iPhone9,2", "iPhone9,3", "iPhone9,4", "iPhone10,1", "iPhone10,2", "iPhone10,4", "iPhone10,5": return "iPhone under X"
  243. default: return "iPhone X or newer"
  244. }
  245. }
  246. func getPrefs(key: String) -> TMessage {
  247. let tMessage = NexilisLite.TMessage()
  248. let me = UserDefaults.standard.string(forKey: "me")
  249. tMessage.mCode = "PPR"
  250. tMessage.mStatus = CoreMessage_TMessageUtil.getTID()
  251. tMessage.mBodies[CoreMessage_TMessageKey.F_PIN] = me
  252. tMessage.mBodies[CoreMessage_TMessageKey.KEY] = key
  253. return tMessage
  254. }
  255. @objc func checkCounter() {
  256. DispatchQueue.main.async { [self] in
  257. if self.viewControllers?.firstIndex(of: secondTab!) != nil {
  258. let counter = queryCountCounter()
  259. let indexSecondTab = self.viewControllers?.firstIndex(of: secondTab!)
  260. let viewSecondTab = self.tabBar.items?[indexSecondTab!].value(forKey: "view") as! UIView
  261. if counter > 0 {
  262. if !indicatorCounterFB.isDescendant(of: viewSecondTab) {
  263. let viewSecondTab = self.tabBar.items?[indexSecondTab!].value(forKey: "view") as! UIView
  264. indicatorCounterFB.backgroundColor = .red
  265. indicatorCounterFB.layer.cornerRadius = 7.5
  266. indicatorCounterFB.clipsToBounds = true
  267. viewSecondTab.addSubview(indicatorCounterFB)
  268. indicatorCounterFB.anchor(top: viewSecondTab.topAnchor, right: viewSecondTab.rightAnchor, paddingRight: 20, height: 15, minWidth: 15, maxWidth: 20)
  269. indicatorCounterFB.addSubview(labelCounterFB)
  270. labelCounterFB.anchor(left: indicatorCounterFB.leftAnchor, right: indicatorCounterFB.rightAnchor, paddingLeft: 5, paddingRight: 5, centerX: indicatorCounterFB.centerXAnchor, centerY: indicatorCounterFB.centerYAnchor)
  271. labelCounterFB.font = .systemFont(ofSize: 10)
  272. labelCounterFB.textColor = .white
  273. }
  274. if counter > 99 {
  275. labelCounterFB.text = "99+"
  276. } else {
  277. labelCounterFB.text = "\(counter)"
  278. }
  279. } else {
  280. if indicatorCounterFB.isDescendant(of: viewSecondTab) {
  281. indicatorCounterFB.removeFromSuperview()
  282. }
  283. }
  284. }
  285. }
  286. }
  287. private func queryCountCounter() -> Int32 {
  288. var counter: Int32?
  289. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  290. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT SUM(counter) FROM MESSAGE_SUMMARY"), cursor.next() {
  291. counter = cursor.int(forColumnIndex: 0)
  292. cursor.close()
  293. }
  294. })
  295. return counter ?? 0
  296. }
  297. // override func viewDidLayoutSubviews() {
  298. // super.viewDidLayoutSubviews()
  299. // tabBar.frame.size.height = 65
  300. // tabBar.frame.origin.y = view.frame.height - 65
  301. // }
  302. func settingDelegate() {
  303. if self.viewControllers?.firstIndex(of: fourthTab!) == nil {
  304. let vc = fourthTab!
  305. vc.notInTab = true
  306. self.navigationController?.show(vc, sender: nil)
  307. } else {
  308. self.selectedIndex = (self.viewControllers?.firstIndex(of: fourthTab!))!
  309. }
  310. }
  311. static var alertChangeProfile = LibAlertController()
  312. public static func checkIsChangePerson() -> Bool {
  313. let isChangeProfile = Utils.getSetProfile()
  314. if !isChangeProfile {
  315. alertChangeProfile.dismiss(animated: false)
  316. alertChangeProfile = LibAlertController(title: "Change Profile".localized(), message: "You must change your name to use this feature".localized().localized(), preferredStyle: .alert)
  317. alertChangeProfile.addAction(UIAlertAction(title: "Cancel".localized(), style: .destructive, handler: {_ in
  318. if ViewController.def?.viewControllers?.firstIndex(of: (ViewController.def?.firstTab)!) == ViewController.def?.selectedIndex {
  319. ViewController.def?.firstTab?.webView?.evaluateJavaScript("if(resumeAll){resumeAll();}")
  320. }
  321. if ViewController.def?.viewControllers?.firstIndex(of: (ViewController.def?.thirdTab)!) == ViewController.def?.selectedIndex {
  322. ViewController.def?.thirdTab?.webView?.evaluateJavaScript("if(resumeAll){resumeAll();}")
  323. }
  324. }))
  325. alertChangeProfile.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: {(_) in
  326. ViewController.resetTabSelected()
  327. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "signupsignin") as! SignUpSignIn
  328. controller.forceLogin = true
  329. controller.isDismiss = { newThumb in
  330. FirstTabViewController.forceRefresh = true
  331. ThirdTabViewController.forceRefresh = true
  332. FirstTabViewController.showModal = false
  333. ThirdTabViewController.showModal = false
  334. }
  335. let navigationController = UINavigationController(rootViewController: controller)
  336. navigationController.modalPresentationStyle = .fullScreen
  337. navigationController.navigationBar.tintColor = .white
  338. navigationController.navigationBar.barTintColor = .mainColor
  339. navigationController.navigationBar.isTranslucent = false
  340. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  341. navigationController.navigationBar.barStyle = .black
  342. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  343. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  344. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  345. navigationController.navigationBar.titleTextAttributes = textAttributes
  346. navigationController.view.backgroundColor = .mainColor
  347. ViewController.def?.show(b: false)
  348. ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  349. ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  350. let rootVC = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
  351. if rootVC?.presentedViewController == nil {
  352. rootVC?.present(navigationController, animated: true, completion: nil)
  353. } else {
  354. rootVC?.presentedViewController?.present(navigationController, animated: true, completion: nil)
  355. }
  356. }))
  357. let rootVC = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
  358. if rootVC?.presentedViewController == nil {
  359. rootVC?.present(alertChangeProfile, animated: true, completion: nil)
  360. } else {
  361. rootVC?.presentedViewController?.present(alertChangeProfile, animated: true, completion: nil)
  362. }
  363. return false
  364. }
  365. return true
  366. }
  367. public static func resetTabSelected(){
  368. ViewController.isTab1 = true
  369. ViewController.isTab2 = false
  370. ViewController.isTab3 = false
  371. ViewController.isTab4 = false
  372. // if ViewController.isTab1 {
  373. // ViewController.imageTab1.image = UIImage(named: "tab_1_nexilis")!
  374. // }
  375. // else {
  376. // ViewController.imageTab1.image = UIImage(named: "tab_1_nexilis_off")!
  377. // }
  378. // if ViewController.isTab2 {
  379. // ViewController.imageTab2.image = UIImage(named: "tab_2_nexilis")!
  380. // }
  381. // else {
  382. // ViewController.imageTab2.image = UIImage(named: "tab_2_nexilis_off")!
  383. // }
  384. // if ViewController.isTab3 {
  385. // ViewController.imageTab3.image = UIImage(named: "tab_3_nexilis")!
  386. // }
  387. // else {
  388. // ViewController.imageTab3.image = UIImage(named: "tab_3_nexilis_off")!
  389. // }
  390. // if ViewController.isTab4 {
  391. // ViewController.imageTab4.image = UIImage(named: "tab_4_nexilis")!
  392. // }
  393. // else {
  394. // ViewController.imageTab4.image = UIImage(named: "tab_4_nexilis_off")!
  395. // }
  396. }
  397. override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
  398. let cpaasMode = PrefsUtil.getCpaasMode()
  399. let customTab = PrefsUtil.getCustomTab().split(separator: ",")
  400. if(cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX){
  401. if(customTab.count == 2){
  402. ViewController.isTab1 = item == tabBar.items?[0]
  403. ViewController.isTab2 = item == tabBar.items?[2]
  404. }
  405. else if(customTab.count == 3){
  406. ViewController.isTab1 = item == tabBar.items?[0]
  407. ViewController.isTab2 = item == tabBar.items?[2]
  408. ViewController.isTab3 = item == tabBar.items?[3]
  409. }
  410. else if(customTab.count == 4){
  411. ViewController.isTab1 = item == tabBar.items?[0]
  412. ViewController.isTab2 = item == tabBar.items?[1]
  413. ViewController.isTab3 = item == tabBar.items?[3]
  414. ViewController.isTab4 = item == tabBar.items?[4]
  415. }
  416. }
  417. else{
  418. ViewController.isTab1 = item == tabBar.items?[0]
  419. ViewController.isTab2 = item == tabBar.items?[1]
  420. if(customTab.count > 2){
  421. ViewController.isTab3 = item == tabBar.items?[2]
  422. }
  423. if(customTab.count > 3){
  424. ViewController.isTab4 = item == tabBar.items?[3]
  425. }
  426. }
  427. }
  428. func createMidFloatingButton(){
  429. var minYIpX: CGFloat = 0
  430. let iPhoneModel = ViewController.getiPhoneModel()
  431. if iPhoneModel == "iPhone X or newer" {
  432. minYIpX += 20
  433. }
  434. ViewController.chatButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: 45, height: 45))
  435. ViewController.chatButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  436. ViewController.chatButton.layer.shadowColor = UIColor.black.cgColor
  437. ViewController.chatButton.layer.shadowOpacity = 0.1
  438. ViewController.chatButton.layer.shadowOffset = CGSize(width: 4, height: 4)
  439. ViewController.chatButton.addTarget(self, action: #selector(chatTap), for: .touchUpInside)
  440. ViewController.callButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: 45, height: 45))
  441. ViewController.callButton.setBackgroundImage(UIImage(named: "pb_button_call", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  442. ViewController.callButton.layer.shadowColor = UIColor.black.cgColor
  443. ViewController.callButton.layer.shadowOpacity = 0.1
  444. ViewController.callButton.layer.shadowOffset = CGSize(width: 4, height: 4)
  445. ViewController.callButton.addTarget(self, action: #selector(callTap), for: .touchUpInside)
  446. ViewController.ccButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: 45, height: 45))
  447. ViewController.ccButton.setBackgroundImage(UIImage(named: "pb_button_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  448. ViewController.ccButton.layer.shadowColor = UIColor.black.cgColor
  449. ViewController.ccButton.layer.shadowOpacity = 0.1
  450. ViewController.ccButton.layer.shadowOffset = CGSize(width: 4, height: 4)
  451. ViewController.ccButton.addTarget(self, action: #selector(ccTap), for: .touchUpInside)
  452. ViewController.streamingButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: 45, height: 45))
  453. ViewController.streamingButton.setBackgroundImage(UIImage(named: "pb_button_stream", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  454. ViewController.streamingButton.layer.shadowColor = UIColor.black.cgColor
  455. ViewController.streamingButton.layer.shadowOpacity = 0.1
  456. ViewController.streamingButton.layer.shadowOffset = CGSize(width: 4, height: 4)
  457. ViewController.streamingButton.addTarget(self, action: #selector(streamTap), for: .touchUpInside)
  458. ViewController.postButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: 45, height: 45))
  459. ViewController.postButton.setBackgroundImage(UIImage(named: "pb_button_post", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  460. ViewController.postButton.layer.shadowColor = UIColor.black.cgColor
  461. ViewController.postButton.layer.shadowOpacity = 0.1
  462. ViewController.postButton.layer.shadowOffset = CGSize(width: 4, height: 4)
  463. ViewController.postButton.addTarget(self, action: #selector(postTap), for: .touchUpInside)
  464. let buttonCenterX = self.view.bounds.width / 2
  465. let buttonCenterY = self.view.bounds.height - self.tabBar.bounds.height
  466. //print("buttonCenterX \(buttonCenterX)")
  467. //print("buttonCenterY \(buttonCenterY)")
  468. ViewController.middleButton = UIButton(frame: CGRect(x: buttonCenterX - 40 , y: buttonCenterY - 40, width: 80, height: 80))
  469. if PrefsUtil.getIconDock() != nil {
  470. DispatchQueue.global().async {
  471. ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getUrlDock()!)!) { data, response, error in
  472. guard let data = data, error == nil else { return }
  473. // always update the UI from the main thread
  474. DispatchQueue.main.async() {
  475. ViewController.middleButton.setBackgroundImage(UIImage(data: data), for: .normal)
  476. }
  477. }
  478. }
  479. } else {
  480. ViewController.middleButton.setBackgroundImage(UIImage(named: "pb_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  481. }
  482. ViewController.middleButton.layer.shadowColor = UIColor.black.cgColor
  483. ViewController.middleButton.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
  484. ViewController.middleButton.layer.shadowOpacity = 1.0
  485. ViewController.middleButton.layer.shadowRadius = 5.0
  486. ViewController.middleButton.layer.masksToBounds = false
  487. ViewController.middleButton.layer.cornerRadius = 4.0
  488. ViewController.middleButton.addTarget(self, action: #selector(middleBtnTapped), for: .touchUpInside)
  489. let longPressMidButton = UILongPressGestureRecognizer(target: self, action: #selector(longPressMidBtn(gestureRecognizer:)))
  490. ViewController.middleButton.addGestureRecognizer(longPressMidButton)
  491. self.view.addSubview(ViewController.chatButton)
  492. self.view.addSubview(ViewController.callButton)
  493. self.view.addSubview(ViewController.ccButton)
  494. self.view.addSubview(ViewController.postButton)
  495. self.view.addSubview(ViewController.streamingButton)
  496. self.view.addSubview(ViewController.middleButton)
  497. ViewController.hideDockedButton()
  498. }
  499. @objc func longPressMidBtn(gestureRecognizer: UILongPressGestureRecognizer) {
  500. if gestureRecognizer.state == .began {
  501. if self.viewControllers?.firstIndex(of: fourthTab!) == nil {
  502. let vc = fourthTab!
  503. vc.notInTab = true
  504. self.navigationController?.show(vc, sender: nil)
  505. } else {
  506. self.selectedIndex = (self.viewControllers?.firstIndex(of: fourthTab!))!
  507. }
  508. }
  509. }
  510. func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
  511. if(viewController == secondTab){
  512. if(!ViewController.checkIsChangePerson()){
  513. return false
  514. }
  515. }
  516. return true
  517. }
  518. func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
  519. if viewController != secondTab {
  520. let idxTabChat = self.viewControllers?.firstIndex(where: {$0 == secondTab})
  521. if idxTabChat != nil {
  522. let vcTabChats = self.viewControllers![idxTabChat!] as! SecondTabViewController
  523. if vcTabChats.searchController.isActive {
  524. vcTabChats.searchController.isActive = false
  525. }
  526. }
  527. }
  528. let cpaasMode = PrefsUtil.getCpaasMode()
  529. var childrenMenu = [UIAction]()
  530. if(cpaasMode == PrefsUtil.CPAAS_MODE_BURGER){
  531. //print("cpaas mode burger")
  532. childrenMenu.append(contentsOf: [
  533. UIAction(title: "Contact Center", handler: {[weak self](_) in
  534. self?.ccTap()
  535. }),
  536. UIAction(title: "Chat", handler: {[weak self](_) in
  537. self?.chatTap()
  538. }),
  539. UIAction(title: "Call", handler: {[weak self](_) in
  540. self?.callTap()
  541. }),
  542. UIAction(title: "New Post", handler: {[weak self](_) in
  543. self?.postTap()
  544. }),
  545. UIAction(title: "Live Streaming", handler: {[weak self](_) in
  546. self?.streamTap()
  547. }),
  548. // UIAction(title: "Settings", handler: {[weak self](_) in
  549. // self?.settingTap()
  550. // }),
  551. ])
  552. if let vc = viewController as? SecondTabViewController {
  553. childrenMenu.append(contentsOf: vc.childrenMenu)
  554. }
  555. let menu = UIMenu(title: "", children: childrenMenu)
  556. if PrefsUtil.getIconDock() != nil {
  557. DispatchQueue.global().async {
  558. ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getUrlDock()!)!) { data, response, error in
  559. guard let data = data, error == nil else { return }
  560. // always update the UI from the main thread
  561. DispatchQueue.main.async() { [self] in
  562. navigationItem.rightBarButtonItem = UIBarButtonItem(image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), primaryAction: .none, menu: menu)
  563. }
  564. }
  565. }
  566. } else {
  567. navigationItem.rightBarButtonItem = UIBarButtonItem(image: resizeImage(image: UIImage(named: "pb_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), primaryAction: .none, menu: menu)
  568. }
  569. }
  570. }
  571. override func viewWillAppear(_ animated: Bool) {
  572. if !firstLoad {
  573. willappear()
  574. } else {
  575. firstLoad = false
  576. }
  577. }
  578. func willappear() {
  579. let acceptTerm = PrefsUtil.getTerms()
  580. let enable_privacy_policy = PrefsUtil.getEnablePrivacyPolicy()
  581. if !acceptTerm {
  582. showWelocomeView()
  583. return
  584. } else if enable_privacy_policy && !PrefsUtil.getAgreePrivacyPolicy() {
  585. showPrivacyPolicyView()
  586. return
  587. } else {
  588. if !Utils.getForceAnonymous() && !Utils.getSetProfile() {
  589. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "changeDevice") as! ChangeDeviceViewController
  590. controller.forceLogin = true
  591. let navigationController = UINavigationController(rootViewController: controller)
  592. navigationController.navigationBar.tintColor = .white
  593. navigationController.navigationBar.barTintColor = .mainColor
  594. navigationController.navigationBar.isTranslucent = false
  595. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  596. navigationController.navigationBar.barStyle = .black
  597. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  598. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  599. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  600. navigationController.navigationBar.titleTextAttributes = textAttributes
  601. navigationController.view.backgroundColor = .mainColor
  602. navigationController.modalPresentationStyle = .fullScreen
  603. navigationController.modalTransitionStyle = .crossDissolve
  604. self.present(navigationController, animated: true)
  605. return
  606. }
  607. }
  608. self.selectedViewController?.viewWillAppear(false)
  609. }
  610. func showPrivacyPolicyView() {
  611. if let privacyView = privacyPolicyVC.view {
  612. let bgImage = UIImageView()
  613. privacyView.addSubview(bgImage)
  614. bgImage.anchor(top: privacyView.topAnchor, left: privacyView.leftAnchor, bottom: privacyView.bottomAnchor, right: privacyView.rightAnchor)
  615. bgImage.backgroundColor = .white
  616. DispatchQueue.global().async {
  617. if let listBg = PrefsUtil.getBackground() {
  618. if listBg.isEmpty {
  619. return
  620. }
  621. var bgChoosen = ""
  622. let arrayBg = listBg.split(separator: ",")
  623. bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
  624. ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase() + "/dashboardv2/uploads/background/" + bgChoosen)!) { data, response, error in
  625. guard let data = data, error == nil else { return }
  626. // always update the UI from the main thread
  627. DispatchQueue.main.async() {
  628. bgImage.image = UIImage(data: data)!
  629. }
  630. }
  631. }
  632. }
  633. let containerButton = UIView()
  634. privacyView.addSubview(containerButton)
  635. containerButton.anchor(left: privacyView.safeAreaLayoutGuide.leftAnchor, bottom: privacyView.safeAreaLayoutGuide.bottomAnchor, paddingLeft: 10, paddingBottom: 10, minHeight: 40)
  636. containerButton.rightAnchor.constraint(lessThanOrEqualTo: privacyView.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
  637. containerButton.isUserInteractionEnabled = true
  638. let tapgestureAgree = UITapGestureRecognizer(target: self, action: #selector(tappedOnAgreePrivacy(_ :)))
  639. tapgestureAgree.numberOfTapsRequired = 1
  640. containerButton.addGestureRecognizer(tapgestureAgree)
  641. let imageAgree = UIImageView()
  642. imageAgree.image = UIImage(systemName: "arrow.forward.circle")
  643. imageAgree.tintColor = .black
  644. containerButton.addSubview(imageAgree)
  645. imageAgree.anchor(left: containerButton.leftAnchor, centerY: containerButton.centerYAnchor, width: 40, height: 40)
  646. let titleAgree = UILabel()
  647. titleAgree.text = "Agree and Continue".localized()
  648. titleAgree.textColor = .black
  649. containerButton.addSubview(titleAgree)
  650. titleAgree.anchor(left: imageAgree.rightAnchor, right: containerButton.rightAnchor, paddingLeft: 5, centerY: containerButton.centerYAnchor)
  651. privacyWV.isOpaque = false
  652. privacyWV.backgroundColor = UIColor.clear
  653. privacyWV.scrollView.backgroundColor = UIColor.clear
  654. //print("URL: \(PrefsUtil.getURLPrivacyPolicy())")
  655. let lang = UserDefaults.standard.string(forKey: "i18n_language")
  656. var urlPrivacyPolicy = PrefsUtil.getURLPrivacyPolicy()
  657. if lang == "id" {
  658. urlPrivacyPolicy = urlPrivacyPolicy.replacingOccurrences(of: "/en/", with: "/id/")
  659. }
  660. privacyWV.load(URLRequest(url: URL(string: urlPrivacyPolicy)!))
  661. privacyView.addSubview(privacyWV)
  662. privacyWV.navigationDelegate = self
  663. privacyWV.anchor(top: privacyView.safeAreaLayoutGuide.topAnchor, left: privacyView.leftAnchor, right: privacyView.rightAnchor, height: privacyView.bounds.height - 80)
  664. }
  665. privacyPolicyVC.modalPresentationStyle = .fullScreen
  666. privacyPolicyVC.modalTransitionStyle = .crossDissolve
  667. self.present(privacyPolicyVC, animated: true)
  668. }
  669. func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
  670. let js = "(function() { document.body.style.background='transparent'; })();"
  671. privacyWV.evaluateJavaScript(js) { (_, error) in
  672. print(error as Any)
  673. }
  674. }
  675. func showWelocomeView() {
  676. if let viewWelcome = welcomeVC.view {
  677. let bgImage = UIImageView()
  678. viewWelcome.addSubview(bgImage)
  679. bgImage.anchor(top: viewWelcome.topAnchor, left: viewWelcome.leftAnchor, bottom: viewWelcome.bottomAnchor, right: viewWelcome.rightAnchor)
  680. bgImage.backgroundColor = .white
  681. DispatchQueue.global().async {
  682. if let listBg = PrefsUtil.getBackground() {
  683. if listBg.isEmpty {
  684. return
  685. }
  686. var bgChoosen = ""
  687. let arrayBg = listBg.split(separator: ",")
  688. bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
  689. ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase() + "/dashboardv2/uploads/background/" + bgChoosen)!) { data, response, error in
  690. guard let data = data, error == nil else { return }
  691. // always update the UI from the main thread
  692. DispatchQueue.main.async() {
  693. bgImage.image = UIImage(data: data)!
  694. }
  695. }
  696. }
  697. }
  698. let welcomeTitle = UILabel()
  699. welcomeTitle.text = "Welcome to".localized() + " " + (Bundle.main.displayName ?? "")
  700. welcomeTitle.font = .systemFont(ofSize: 25, weight: .bold)
  701. welcomeTitle.numberOfLines = 0
  702. viewWelcome.addSubview(welcomeTitle)
  703. welcomeTitle.anchor(top: viewWelcome.safeAreaLayoutGuide.topAnchor, left: viewWelcome.safeAreaLayoutGuide.leftAnchor, right: viewWelcome.safeAreaLayoutGuide.rightAnchor, paddingTop: 10, paddingLeft: 10, paddingRight: 10)
  704. let logoImage = UIImageView()
  705. logoImage.image = UIImage(named: getHighResolutionAppIconName() ?? "")
  706. viewWelcome.addSubview(logoImage)
  707. logoImage.anchor(centerX: viewWelcome.centerXAnchor, centerY: viewWelcome.centerYAnchor, width: 200, height: 200)
  708. let containerButton = UIView()
  709. viewWelcome.addSubview(containerButton)
  710. containerButton.anchor(left: viewWelcome.safeAreaLayoutGuide.leftAnchor, bottom: viewWelcome.safeAreaLayoutGuide.bottomAnchor, paddingLeft: 10, paddingBottom: 10, minHeight: 40)
  711. containerButton.rightAnchor.constraint(lessThanOrEqualTo: viewWelcome.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
  712. containerButton.isUserInteractionEnabled = true
  713. let tapgestureAgree = UITapGestureRecognizer(target: self, action: #selector(tappedOnAgree(_ :)))
  714. tapgestureAgree.numberOfTapsRequired = 1
  715. containerButton.addGestureRecognizer(tapgestureAgree)
  716. let imageAgree = UIImageView()
  717. imageAgree.image = UIImage(systemName: "arrow.forward.circle")
  718. imageAgree.tintColor = .black
  719. containerButton.addSubview(imageAgree)
  720. imageAgree.anchor(left: containerButton.leftAnchor, centerY: containerButton.centerYAnchor, width: 40, height: 40)
  721. let titleAgree = UILabel()
  722. titleAgree.text = "Agree and Continue".localized()
  723. titleAgree.textColor = .black
  724. containerButton.addSubview(titleAgree)
  725. titleAgree.anchor(left: imageAgree.rightAnchor, right: containerButton.rightAnchor, paddingLeft: 5, centerY: containerButton.centerYAnchor)
  726. let formattedText = String.format(strings: [term], inString: termText)
  727. welcomeDesc.isUserInteractionEnabled = true
  728. welcomeDesc.attributedText = formattedText
  729. welcomeDesc.numberOfLines = 0
  730. viewWelcome.addSubview(welcomeDesc)
  731. welcomeDesc.anchor(left: viewWelcome.safeAreaLayoutGuide.leftAnchor, bottom: containerButton.topAnchor, right: viewWelcome.rightAnchor, paddingLeft: 10, paddingBottom: 10, paddingRight: 10)
  732. let tapgesture = UITapGestureRecognizer(target: self, action: #selector(tappedOnLabelTerms(_ :)))
  733. tapgesture.numberOfTapsRequired = 1
  734. welcomeDesc.addGestureRecognizer(tapgesture)
  735. }
  736. welcomeVC.modalPresentationStyle = .fullScreen
  737. welcomeVC.modalTransitionStyle = .crossDissolve
  738. self.present(welcomeVC, animated: true)
  739. }
  740. func getHighResolutionAppIconName() -> String? {
  741. guard let infoPlist = Bundle.main.infoDictionary else { return nil }
  742. guard let bundleIcons = infoPlist["CFBundleIcons"] as? NSDictionary else { return nil }
  743. guard let bundlePrimaryIcon = bundleIcons["CFBundlePrimaryIcon"] as? NSDictionary else { return nil }
  744. guard let bundleIconFiles = bundlePrimaryIcon["CFBundleIconFiles"] as? NSArray else { return nil }
  745. guard let appIcon = bundleIconFiles.lastObject as? String else { return nil }
  746. return appIcon
  747. }
  748. func showWebviewTerm() {
  749. termVC = UIViewController()
  750. if let viewTerm = termVC!.view {
  751. let webView = WKWebView()
  752. let lang = UserDefaults.standard.string(forKey: "i18n_language")
  753. var urlTerm = "https://newuniverse.io/newuniverse-tos"
  754. if lang == "id" {
  755. urlTerm = "https://newuniverse.io/newuniverse-tos-id"
  756. }
  757. let url = URL (string: urlTerm)
  758. let requestObj = URLRequest(url: url!)
  759. webView.load(requestObj)
  760. viewTerm.addSubview(webView)
  761. webView.anchor(top: viewTerm.safeAreaLayoutGuide.topAnchor, left: viewTerm.safeAreaLayoutGuide.leftAnchor, bottom: viewTerm.safeAreaLayoutGuide.bottomAnchor, right: viewTerm.safeAreaLayoutGuide.rightAnchor)
  762. }
  763. let navigationController = UINavigationController(rootViewController: termVC!)
  764. navigationController.navigationBar.tintColor = .mainColor
  765. navigationController.navigationBar.barTintColor = .white
  766. navigationController.navigationBar.isTranslucent = false
  767. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.mainColor]
  768. navigationController.navigationBar.titleTextAttributes = textAttributes
  769. navigationController.view.backgroundColor = .white
  770. termVC!.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Close".localized(), style: .plain, target: self, action: #selector(closeTerm))
  771. welcomeVC.present(navigationController, animated: true)
  772. }
  773. @objc func closeTerm() {
  774. termVC!.dismiss(animated: true)
  775. }
  776. @objc func tappedOnLabelTerms(_ gesture: UITapGestureRecognizer) {
  777. let termString = termText as NSString
  778. let termRange = termString.range(of: term)
  779. let tapLocation = gesture.location(in: welcomeDesc)
  780. let index = welcomeDesc.indexOfAttributedTextCharacterAtPoint(point: tapLocation)
  781. if checkRange(termRange, contain: index) == true {
  782. showWebviewTerm()
  783. return
  784. }
  785. }
  786. @objc func tappedOnAgree(_ gesture: UITapGestureRecognizer) {
  787. PrefsUtil.setTerms(value: true)
  788. welcomeVC.dismiss(animated: true)
  789. }
  790. @objc func tappedOnAgreePrivacy(_ gesture: UITapGestureRecognizer) {
  791. PrefsUtil.setAgreePrivacyPolicy(value: true)
  792. privacyPolicyVC.dismiss(animated: true)
  793. }
  794. func checkRange(_ range: NSRange, contain index: Int) -> Bool {
  795. return index > range.location && index < range.location + range.length
  796. }
  797. @objc func middleBtnTapped() {
  798. ViewController.expandButton()
  799. }
  800. public func show(b: Bool) {
  801. if(!b){
  802. if(ViewController.isExpandButton){
  803. ViewController.expandButton()
  804. }
  805. }
  806. }
  807. @objc func ccTap() {
  808. //print("ccTap")
  809. if(ViewController.checkIsChangePerson()){
  810. show(b: false)
  811. ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  812. ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  813. if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 2 {
  814. let package_id = ViewController.listPullFB[2].split(separator: "|")[0]
  815. var app_id = ""
  816. if ViewController.listPullFB[2].split(separator: "|").count > 1 {
  817. app_id = String(ViewController.listPullFB[2].split(separator: "|")[1])
  818. }
  819. if package_id.contains("_fb") {
  820. let indexTap = Int(String(package_id.split(separator: "_")[1]).substring(from: 2, to: 2))!
  821. if indexTap == 99 {
  822. openTabPost()
  823. } else {
  824. if indexTap == 2 {
  825. let url = package_id.components(separatedBy: "_")[2]
  826. Nexilis.buttonClicked(index: indexTap, id: url)
  827. } else {
  828. Nexilis.buttonClicked(index: indexTap)
  829. }
  830. }
  831. } else {
  832. if !app_id.isEmpty {
  833. Nexilis.buttonClicked(index: 0, id: app_id)
  834. }
  835. }
  836. } else {
  837. Nexilis.buttonClicked(index: 9)
  838. }
  839. }
  840. }
  841. @objc func streamTap() {
  842. //print("streamTap")
  843. if(ViewController.checkIsChangePerson()){
  844. show(b: false)
  845. ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  846. ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  847. if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 4 {
  848. let package_id = ViewController.listPullFB[4].split(separator: "|")[0]
  849. var app_id = ""
  850. if ViewController.listPullFB[4].split(separator: "|").count > 1 {
  851. app_id = String(ViewController.listPullFB[4].split(separator: "|")[1])
  852. }
  853. if package_id.contains("_fb") {
  854. let indexTap = Int(String(package_id.split(separator: "_")[1]).substring(from: 2, to: 2))!
  855. if indexTap == 99 {
  856. openTabPost()
  857. } else {
  858. if indexTap == 2 {
  859. let url = package_id.components(separatedBy: "_")[2]
  860. Nexilis.buttonClicked(index: indexTap, id: url)
  861. } else {
  862. Nexilis.buttonClicked(index: indexTap)
  863. }
  864. }
  865. } else {
  866. if !app_id.isEmpty {
  867. Nexilis.buttonClicked(index: 0, id: app_id)
  868. }
  869. }
  870. } else {
  871. Nexilis.buttonClicked(index: 8)
  872. }
  873. }
  874. }
  875. @objc func callTap() {
  876. //print("callTap")
  877. if(ViewController.checkIsChangePerson()){
  878. show(b: false)
  879. ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  880. ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  881. if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 1 {
  882. let package_id = ViewController.listPullFB[1].split(separator: "|")[0]
  883. var app_id = ""
  884. if ViewController.listPullFB[1].split(separator: "|").count > 1 {
  885. app_id = String(ViewController.listPullFB[1].split(separator: "|")[1])
  886. }
  887. if package_id.contains("_fb") {
  888. let indexTap = Int(String(package_id.split(separator: "_")[1]).substring(from: 2, to: 2))!
  889. if indexTap == 99 {
  890. openTabPost()
  891. } else {
  892. if indexTap == 2 {
  893. let url = package_id.components(separatedBy: "_")[2]
  894. Nexilis.buttonClicked(index: indexTap, id: url)
  895. } else {
  896. Nexilis.buttonClicked(index: indexTap)
  897. }
  898. }
  899. } else {
  900. if !app_id.isEmpty {
  901. Nexilis.buttonClicked(index: 0, id: app_id)
  902. }
  903. }
  904. } else {
  905. Nexilis.buttonClicked(index: 7)
  906. }
  907. }
  908. }
  909. @objc func chatTap() {
  910. //print("chatTap")
  911. // APIS.openWhiteboard()
  912. // return
  913. if(ViewController.checkIsChangePerson()){
  914. show(b: false)
  915. ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  916. ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  917. if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 0 {
  918. let package_id = ViewController.listPullFB[0].split(separator: "|")[0]
  919. var app_id = ""
  920. if ViewController.listPullFB[0].split(separator: "|").count > 1 {
  921. app_id = String(ViewController.listPullFB[0].split(separator: "|")[1])
  922. }
  923. if package_id.contains("_fb") {
  924. let indexTap = Int(String(package_id.split(separator: "_")[1]).substring(from: 2, to: 2))!
  925. if indexTap == 99 {
  926. openTabPost()
  927. } else {
  928. if indexTap == 2 {
  929. let url = package_id.components(separatedBy: "_")[2]
  930. Nexilis.buttonClicked(index: indexTap, id: url)
  931. } else {
  932. Nexilis.buttonClicked(index: indexTap)
  933. }
  934. }
  935. } else {
  936. if !app_id.isEmpty {
  937. Nexilis.buttonClicked(index: 0, id: app_id)
  938. }
  939. }
  940. } else {
  941. Nexilis.buttonClicked(index: 6)
  942. }
  943. }
  944. }
  945. @objc func postTap() {
  946. if(ViewController.checkIsChangePerson()){
  947. show(b: false)
  948. ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  949. ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  950. if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 3 {
  951. let package_id = ViewController.listPullFB[3].split(separator: "|")[0]
  952. var app_id = ""
  953. if ViewController.listPullFB[3].split(separator: "|").count > 1 {
  954. app_id = String(ViewController.listPullFB[3].split(separator: "|")[1])
  955. }
  956. if package_id.contains("_fb") {
  957. let indexTap = Int(String(package_id.split(separator: "_")[1]).substring(from: 2, to: 2))!
  958. if indexTap == 99 {
  959. openTabPost()
  960. } else {
  961. if indexTap == 2 {
  962. let url = package_id.components(separatedBy: "_")[2]
  963. Nexilis.buttonClicked(index: indexTap, id: url)
  964. } else {
  965. Nexilis.buttonClicked(index: indexTap)
  966. }
  967. }
  968. } else {
  969. if !app_id.isEmpty {
  970. Nexilis.buttonClicked(index: 0, id: app_id)
  971. }
  972. }
  973. } else {
  974. openTabPost()
  975. }
  976. }
  977. }
  978. func openTabPost() {
  979. let customTab = PrefsUtil.getCustomTab().split(separator: ",")
  980. let cpaasMode = PrefsUtil.getCpaasMode()
  981. var i = 0
  982. var j = 0
  983. //print("custom tab post tap = \(customTab)")
  984. while j < customTab.count {
  985. if(((i == 1 && customTab.count == 3) || i == 2) &&
  986. (cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)){
  987. }
  988. else {
  989. if customTab[j] == "3" {
  990. break
  991. }
  992. j += 1
  993. }
  994. i += 1
  995. }
  996. if(j < customTab.count){
  997. self.selectedIndex = i
  998. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1), execute: {
  999. let me = UserDefaults.standard.string(forKey: "me")
  1000. let address = "\(PrefsUtil.getURLBase())nexilis/pages/tab5-new-post?f_pin=\(me ?? "")"
  1001. self.thirdTab?.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.tab3)')}")
  1002. self.thirdTab?.webView.evaluateJavaScript("window.location = '\(address)'")
  1003. })
  1004. }
  1005. }
  1006. static func pullActionButton() {
  1007. if datePullFB == nil || Int(Date().timeIntervalSince(datePullFB!)) >= 60 {
  1008. datePullFB = Date()
  1009. DispatchQueue.global().async {
  1010. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.pullFloatingButton(), timeout: 30 * 1000) {
  1011. if response.isOk() {
  1012. let data = response.getBody(key: CoreMessage_TMessageKey.DATA, default_value: "")
  1013. if !data.isEmpty {
  1014. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  1015. DispatchQueue.main.async { [self] in
  1016. listPullFB.removeAll()
  1017. if jsonArray.count != 0 {
  1018. var count = 0
  1019. for json in jsonArray {
  1020. let package_id = json["package_act"] as! String
  1021. let app_id = (json["app_id"] as? String) ?? ""
  1022. let icon = (json["icon"] as? String) ?? ""
  1023. listPullFB.append("\(package_id)|\(app_id)")
  1024. if count == 0 {
  1025. if !icon.isEmpty {
  1026. DispatchQueue.global().async {
  1027. ViewController.getDataImageFromUrl(from: URL(string: "https://newuniverse.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
  1028. guard let data = data, error == nil else { return }
  1029. // always update the UI from the main thread
  1030. DispatchQueue.main.async() {
  1031. ViewController.chatButton.setBackgroundImage(UIImage(data: data), for: .normal)
  1032. }
  1033. }
  1034. }
  1035. } else {
  1036. ViewController.chatButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  1037. }
  1038. } else if count == 1 {
  1039. if !icon.isEmpty {
  1040. DispatchQueue.global().async {
  1041. ViewController.getDataImageFromUrl(from: URL(string: "https://newuniverse.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
  1042. guard let data = data, error == nil else { return }
  1043. // always update the UI from the main thread
  1044. DispatchQueue.main.async() {
  1045. ViewController.callButton.setBackgroundImage(UIImage(data: data), for: .normal)
  1046. }
  1047. }
  1048. }
  1049. } else {
  1050. ViewController.callButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  1051. }
  1052. } else if count == 2 {
  1053. if !icon.isEmpty {
  1054. DispatchQueue.global().async {
  1055. ViewController.getDataImageFromUrl(from: URL(string: "https://newuniverse.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
  1056. guard let data = data, error == nil else { return }
  1057. // always update the UI from the main thread
  1058. DispatchQueue.main.async() {
  1059. ViewController.ccButton.setBackgroundImage(UIImage(data: data), for: .normal)
  1060. }
  1061. }
  1062. }
  1063. } else {
  1064. ViewController.ccButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  1065. }
  1066. } else if count == 3 {
  1067. if !icon.isEmpty {
  1068. DispatchQueue.global().async {
  1069. ViewController.getDataImageFromUrl(from: URL(string: "https://newuniverse.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
  1070. guard let data = data, error == nil else { return }
  1071. // always update the UI from the main thread
  1072. DispatchQueue.main.async() {
  1073. ViewController.postButton.setBackgroundImage(UIImage(data: data), for: .normal)
  1074. }
  1075. }
  1076. }
  1077. } else {
  1078. ViewController.postButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  1079. }
  1080. } else if count == 4 {
  1081. if !icon.isEmpty {
  1082. DispatchQueue.global().async {
  1083. ViewController.getDataImageFromUrl(from: URL(string: "https://newuniverse.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
  1084. guard let data = data, error == nil else { return }
  1085. // always update the UI from the main thread
  1086. DispatchQueue.main.async() {
  1087. ViewController.streamingButton.setBackgroundImage(UIImage(data: data), for: .normal)
  1088. }
  1089. }
  1090. }
  1091. } else {
  1092. ViewController.streamingButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
  1093. }
  1094. }
  1095. count += 1
  1096. }
  1097. }
  1098. }
  1099. }
  1100. }
  1101. }
  1102. }
  1103. }
  1104. }
  1105. }
  1106. public static func showDockedButton() {
  1107. ViewController.chatButton.isHidden = false
  1108. ViewController.callButton.isHidden = false
  1109. ViewController.ccButton.isHidden = false
  1110. ViewController.streamingButton.isHidden = false
  1111. ViewController.postButton.isHidden = false
  1112. }
  1113. public static func hideDockedButton() {
  1114. ViewController.chatButton.isHidden = true
  1115. ViewController.callButton.isHidden = true
  1116. ViewController.ccButton.isHidden = true
  1117. ViewController.streamingButton.isHidden = true
  1118. ViewController.postButton.isHidden = true
  1119. }
  1120. public static func expandButton() {
  1121. let cpaasMode = PrefsUtil.getCpaasMode()
  1122. if cpaasMode != PrefsUtil.CPAAS_MODE_DOCKED && cpaasMode != PrefsUtil.CPAAS_MODE_MIX {
  1123. return
  1124. }
  1125. if ViewController.alwaysHideButton && !ViewController.isExpandButton {
  1126. return
  1127. }
  1128. var minYIpX: CGFloat = 0
  1129. let iPhoneModel = getiPhoneModel()
  1130. if iPhoneModel == "iPhone X or newer" {
  1131. minYIpX += 20
  1132. }
  1133. if ViewController.isExpandButton {
  1134. ViewController.isExpandButton = false
  1135. let xChatPosition = ViewController.chatButton.frame.origin.x + 90
  1136. let yChatPosition = ViewController.chatButton.frame.origin.y + 20
  1137. let xCallPosition = ViewController.callButton.frame.origin.x + 55
  1138. let yCallPosition = ViewController.callButton.frame.origin.y + 70
  1139. let xCCPosition = ViewController.ccButton.frame.origin.x
  1140. let yCCPosition = ViewController.ccButton.frame.origin.y + 90
  1141. let xPostPosition = ViewController.postButton.frame.origin.x - 55
  1142. let yPostPosition = ViewController.postButton.frame.origin.y + 70
  1143. let xStreamingPosition = ViewController.streamingButton.frame.origin.x - 90
  1144. let yStreamingPosition = ViewController.streamingButton.frame.origin.y + 20
  1145. UIView.animate(withDuration: 0.5, animations: {
  1146. // if !ViewController.isBlue {
  1147. // ViewController.middleButton.transform = CGAffineTransform(rotationAngle: 0)
  1148. // }
  1149. ViewController.chatButton.frame.origin = CGPoint(x: xChatPosition, y: yChatPosition + minYIpX)
  1150. ViewController.callButton.frame.origin = CGPoint(x: xCallPosition, y: yCallPosition + minYIpX)
  1151. ViewController.ccButton.frame.origin = CGPoint(x: xCCPosition, y: yCCPosition + minYIpX)
  1152. ViewController.streamingButton.frame.origin = CGPoint(x: xStreamingPosition, y: yStreamingPosition + minYIpX)
  1153. ViewController.postButton.frame.origin = CGPoint(x: xPostPosition, y: yPostPosition + minYIpX)
  1154. })
  1155. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
  1156. if !ViewController.isExpandButton {
  1157. ViewController.hideDockedButton()
  1158. }
  1159. })
  1160. } else {
  1161. ViewController.isExpandButton = true
  1162. ViewController.showDockedButton()
  1163. let xChatPosition = ViewController.chatButton.frame.origin.x - 90
  1164. let yChatPosition = ViewController.chatButton.frame.origin.y - 20
  1165. let xCallPosition = ViewController.callButton.frame.origin.x - 55
  1166. let yCallPosition = ViewController.callButton.frame.origin.y - 70
  1167. let xCCPosition = ViewController.ccButton.frame.origin.x
  1168. let yCCPosition = ViewController.ccButton.frame.origin.y - 90
  1169. let xPostPosition = ViewController.postButton.frame.origin.x + 55
  1170. let yPostPosition = ViewController.postButton.frame.origin.y - 70
  1171. let xStreamingPosition = ViewController.streamingButton.frame.origin.x + 90
  1172. let yStreamingPosition = ViewController.streamingButton.frame.origin.y - 20
  1173. UIView.animate(withDuration: 0.5, animations: {
  1174. // if !ViewController.isBlue{
  1175. // ViewController.middleButton.transform = CGAffineTransform(rotationAngle: .pi / 2)
  1176. // }
  1177. ViewController.chatButton.frame.origin = CGPoint(x: xChatPosition, y: yChatPosition - minYIpX)
  1178. ViewController.callButton.frame.origin = CGPoint(x: xCallPosition, y: yCallPosition - minYIpX)
  1179. ViewController.ccButton.frame.origin = CGPoint(x: xCCPosition, y: yCCPosition - minYIpX)
  1180. ViewController.streamingButton.frame.origin = CGPoint(x: xStreamingPosition, y: yStreamingPosition - minYIpX)
  1181. ViewController.postButton.frame.origin = CGPoint(x: xPostPosition, y: yPostPosition - minYIpX)
  1182. })
  1183. }
  1184. }
  1185. public static func removeMiddleButton() {
  1186. // ViewController.chatButton.removeFromSuperview()
  1187. // ViewController.callButton.removeFromSuperview()
  1188. // ViewController.ccButton.removeFromSuperview()
  1189. // ViewController.streamingButton.removeFromSuperview()
  1190. // ViewController.postButton.removeFromSuperview()
  1191. ViewController.middleButton.isHidden = true
  1192. }
  1193. public static func getDataImageFromUrl(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
  1194. URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
  1195. }
  1196. }
  1197. class EmptyTabViewController: UIViewController {
  1198. override func viewDidLoad() {
  1199. }
  1200. }
  1201. extension Bundle {
  1202. // Name of the app - title under the icon.
  1203. var displayName: String? {
  1204. return object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ??
  1205. object(forInfoDictionaryKey: "CFBundleName") as? String
  1206. }
  1207. }
  1208. extension BinaryInteger {
  1209. var degreesToRadians: CGFloat { CGFloat(self) * .pi / 180 }
  1210. }
  1211. extension FloatingPoint {
  1212. var degreesToRadians: Self { self * .pi / 180 }
  1213. var radiansToDegrees: Self { self * 180 / .pi }
  1214. }
  1215. extension UIImage {
  1216. class func imageWithColor(color: UIColor, size: CGSize) -> UIImage {
  1217. let rect: CGRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
  1218. UIGraphicsBeginImageContextWithOptions(size, false, 0)
  1219. color.setFill()
  1220. UIRectFill(rect)
  1221. let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
  1222. UIGraphicsEndImageContext()
  1223. return image
  1224. }
  1225. }
  1226. extension String {
  1227. static func format(strings: [String],
  1228. italicFont: UIFont = UIFont.italicSystemFont(ofSize: 12),
  1229. italicColor: UIColor = UIColor.systemGreen,
  1230. inString string: String,
  1231. font: UIFont = UIFont.systemFont(ofSize: 12),
  1232. color: UIColor = UIColor.black) -> NSAttributedString {
  1233. let attributedString =
  1234. NSMutableAttributedString(string: string,
  1235. attributes: [
  1236. NSAttributedString.Key.font: font,
  1237. NSAttributedString.Key.foregroundColor: color])
  1238. let italicFontAttribute = [NSAttributedString.Key.font: italicFont, NSAttributedString.Key.foregroundColor: italicColor]
  1239. for italic in strings {
  1240. attributedString.addAttributes(italicFontAttribute, range: (string as NSString).range(of: italic))
  1241. }
  1242. return attributedString
  1243. }
  1244. }
  1245. extension UILabel {
  1246. func indexOfAttributedTextCharacterAtPoint(point: CGPoint) -> Int {
  1247. assert(self.attributedText != nil, "This method is developed for attributed string")
  1248. let textStorage = NSTextStorage(attributedString: self.attributedText!)
  1249. let layoutManager = NSLayoutManager()
  1250. textStorage.addLayoutManager(layoutManager)
  1251. let textContainer = NSTextContainer(size: self.frame.size)
  1252. textContainer.lineFragmentPadding = 0
  1253. textContainer.maximumNumberOfLines = self.numberOfLines
  1254. textContainer.lineBreakMode = self.lineBreakMode
  1255. layoutManager.addTextContainer(textContainer)
  1256. let index = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
  1257. return index
  1258. }
  1259. }