QmeraVideoViewController.swift 81 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526
  1. //
  2. // VideoViewControllerQmera.swift
  3. // Qmera
  4. //
  5. // Created by Akhmad Al Qindi Irsyam on 07/10/21.
  6. //
  7. // Rn
  8. // (Kedip whiteboard)
  9. // extension Whiteboard
  10. // wbVC!.close wbTimer wbBlink
  11. import UIKit
  12. import nuSDKService
  13. import AVFoundation
  14. import NotificationBannerSwift
  15. class QmeraVideoViewController: UIViewController {
  16. var dataPerson: [[String: String?]] = []
  17. var fPin = ""
  18. var wbRoomId = ""
  19. var isInisiator = true
  20. var isSpeaker = true
  21. var isPresent = false
  22. var callFCM = false
  23. var listRemoteViewFix: [UIImageView] = [
  24. UIImageView(),
  25. UIImageView(),
  26. UIImageView(),
  27. UIImageView(),
  28. UIImageView()
  29. ]
  30. var containerLabelName: [UIView] = [
  31. UIView(),
  32. UIView(),
  33. UIView(),
  34. UIView(),
  35. UIView()
  36. ]
  37. let myImage = UIImageView()
  38. let name = UILabel()
  39. let profileImage = UIImageView()
  40. let labelIncomingOutgoing = UILabel()
  41. let buttonDecline = UIButton()
  42. let buttonAccept = UIButton()
  43. let zoomView = UIImageView()
  44. let cameraView = UIImageView()
  45. var constraintLeadingButtonDecline = NSLayoutConstraint()
  46. var constraintBottomButtonDecline = NSLayoutConstraint()
  47. var constraintBottomStackViewToolbar = NSLayoutConstraint()
  48. var constraintLeftStackViewToolbar2 = NSLayoutConstraint()
  49. let stackViewToolbar = UIStackView()
  50. let stackViewToolbar2 = UIStackView()
  51. var onScreenConstraintWB = [NSLayoutConstraint]()
  52. let buttonWB = UIButton()
  53. let buttonChat = UIButton()
  54. var wbVC : WhiteboardViewController?
  55. let buttonAddParticipant = UIButton()
  56. let buttonSpeaker = UIButton()
  57. let buttonRotate = UIButton()
  58. var showStackViewToolbar = true
  59. let scrollRemoteView = UIScrollView()
  60. var isAutoAccept = false
  61. var wbTimer = Timer()
  62. var wbBlink = false
  63. var showNotifCCEnd = false
  64. var transformZoomAfterNewUserMore2 = false
  65. var isAddCall = ""
  66. var ticketId = ""
  67. private var frontCamera = true
  68. var users: [User] = []
  69. let poweredByView: UIStackView = {
  70. let stackView = UIStackView()
  71. stackView.axis = .horizontal
  72. stackView.spacing = 5
  73. return stackView
  74. }()
  75. private var vcTimer = Timer()
  76. private var containerTimerVC = UIView()
  77. private var labelTimerVC = UILabel()
  78. let poweredByLabel: UILabel = {
  79. let label = UILabel()
  80. label.text = "Powered by Nexilis".localized()
  81. return label
  82. }()
  83. let qmeraLogo: UIButton = {
  84. let image = UIImage(named: "Q-Button-PNG", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  85. let button = UIButton()
  86. button.setImage(image, for: .normal)
  87. button.imageView?.contentMode = .scaleAspectFit
  88. button.imageEdgeInsets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
  89. button.contentVerticalAlignment = .fill
  90. button.contentHorizontalAlignment = .fill
  91. // button.frame.size.width = 30
  92. // button.frame.size.height = 30
  93. return button
  94. }()
  95. let nexilisLogo: UIButton = {
  96. let image = UIImage(named: "pb_powered_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  97. let button = UIButton()
  98. button.setImage(image, for: .normal)
  99. button.imageView?.contentMode = .scaleAspectFit
  100. button.imageEdgeInsets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
  101. button.contentVerticalAlignment = .fill
  102. button.contentHorizontalAlignment = .fill
  103. // button.frame.size.width = 30
  104. // button.frame.size.height = 30
  105. return button
  106. }()
  107. deinit {
  108. navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
  109. navigationController?.navigationBar.shadowImage = nil
  110. navigationController?.navigationBar.isTranslucent = false
  111. navigationController?.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  112. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  113. navigationController?.navigationBar.titleTextAttributes = textAttributes
  114. navigationController?.navigationBar.topItem?.backBarButtonItem = nil
  115. navigationController?.interactivePopGestureRecognizer?.isEnabled = true
  116. NotificationCenter.default.removeObserver(self)
  117. }
  118. override func viewWillDisappear(_ animated: Bool) {
  119. if self.isMovingFromParent {
  120. navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
  121. navigationController?.navigationBar.shadowImage = nil
  122. navigationController?.navigationBar.isTranslucent = false
  123. navigationController?.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  124. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  125. navigationController?.navigationBar.titleTextAttributes = textAttributes
  126. navigationController?.navigationBar.topItem?.backBarButtonItem = nil
  127. navigationController?.interactivePopGestureRecognizer?.isEnabled = true
  128. NotificationCenter.default.removeObserver(self)
  129. }
  130. }
  131. override func viewDidLoad() {
  132. super.viewDidLoad()
  133. Nexilis.setWhiteboardReceiver(receiver: self)
  134. self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
  135. let navBarAppearance = UINavigationBarAppearance()
  136. navBarAppearance.configureWithTransparentBackground()
  137. navigationController?.navigationBar.standardAppearance = navBarAppearance
  138. navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
  139. navigationController?.changeAppearance(clear: true)
  140. NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil)
  141. NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
  142. NotificationCenter.default.addObserver(self, selector: #selector(onCallFCM(notification:)), name: NSNotification.Name(rawValue: Nexilis.callFCM), object: nil)
  143. view.backgroundColor = .clear
  144. navigationController?.navigationBar.topItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
  145. navigationController?.interactivePopGestureRecognizer?.isEnabled = false
  146. navigationItem.setHidesBackButton(true, animated: false)
  147. if fPin != ""{
  148. getDataProfile(fPin: fPin)
  149. }
  150. addZoomView()
  151. addCameraView()
  152. addListRemoteView()
  153. addBackgroundIncoming()
  154. addProfileNameCalling()
  155. Calling()
  156. addToolbar()
  157. addTimerVC()
  158. if isAutoAccept {
  159. didTapAcceptCallButton()
  160. }
  161. }
  162. func getDataProfile(fPin: String) {
  163. let query = "SELECT f_pin, first_name, last_name, official_account, image_id, device_id, offline_mode, user_type FROM BUDDY where f_pin = '\(fPin)'"
  164. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  165. if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: query) {
  166. var row: [String: String?] = [:]
  167. if cursorData.next() {
  168. row["f_pin"] = cursorData.string(forColumnIndex: 0)
  169. var name = ""
  170. if let firstname = cursorData.string(forColumnIndex: 1) {
  171. name = firstname
  172. }
  173. if let lastname = cursorData.string(forColumnIndex: 2) {
  174. name = name + " " + lastname
  175. }
  176. row["name"] = name
  177. row["picture"] = cursorData.string(forColumnIndex: 4)
  178. row["isOfficial"] = cursorData.string(forColumnIndex: 3)
  179. row["deviceId"] = cursorData.string(forColumnIndex: 5)
  180. row["isOffline"] = cursorData.string(forColumnIndex: 6)
  181. row["user_type"] = cursorData.string(forColumnIndex: 7)
  182. if fPin != User.getMyPin() {
  183. dataPerson.append(row)
  184. }
  185. } else {
  186. var row: [String: String?] = [:]
  187. row["f_pin"] = fPin
  188. row["name"] = "User".localized()
  189. row["picture"] = ""
  190. row["isOfficial"] = ""
  191. row["deviceId"] = ""
  192. row["isOffline"] = ""
  193. row["user_type"] = ""
  194. dataPerson.append(row)
  195. }
  196. cursorData.close()
  197. } else {
  198. var row: [String: String?] = [:]
  199. row["f_pin"] = fPin
  200. row["name"] = "User".localized()
  201. row["picture"] = ""
  202. row["isOfficial"] = ""
  203. row["deviceId"] = ""
  204. row["isOffline"] = ""
  205. row["user_type"] = ""
  206. dataPerson.append(row)
  207. // if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getAddFriendQRCode(fpin: fPin)), response.isOk() {
  208. // self.getDataProfile(fPin: fPin)
  209. // }
  210. // Nexilis.addFriend (fpin: "\(fPin)") { result in
  211. // if result {
  212. // self.getDataProfile(fPin: fPin)
  213. // } else {
  214. // let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  215. // imageView.tintColor = .white
  216. // let banner = FloatingNotificationBanner(title: "Server busy, please try again later".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
  217. // banner.show()
  218. // }
  219. // }
  220. }
  221. })
  222. }
  223. func addTimerVC() {
  224. view.addSubview(containerTimerVC)
  225. containerTimerVC.anchor(top: view.topAnchor, paddingTop: 20, centerX: view.centerXAnchor, minWidth: 40)
  226. containerTimerVC.makeRoundedView(radius: 8)
  227. containerTimerVC.backgroundColor = .black.withAlphaComponent(0.3)
  228. containerTimerVC.addSubview(labelTimerVC)
  229. labelTimerVC.anchor(left: containerTimerVC.leftAnchor, right: containerTimerVC.rightAnchor, paddingLeft: 8, paddingRight: 8, centerX: containerTimerVC.centerXAnchor, centerY: containerTimerVC.centerYAnchor)
  230. labelTimerVC.textColor = .white
  231. containerTimerVC.isHidden = true
  232. }
  233. func addZoomView() {
  234. view.addSubview(zoomView)
  235. zoomView.translatesAutoresizingMaskIntoConstraints = false
  236. NSLayoutConstraint.activate([
  237. zoomView.topAnchor.constraint(equalTo: view.topAnchor),
  238. zoomView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
  239. zoomView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
  240. zoomView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
  241. ])
  242. zoomView.backgroundColor = .secondaryColor
  243. zoomView.isUserInteractionEnabled = true
  244. zoomView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(hideToolbar)))
  245. }
  246. func addCameraView() {
  247. view.addSubview(cameraView)
  248. // cameraView.frame = CGRect(x: view.frame.width - 130, y: 20, width: 120, height: 160)
  249. cameraView.translatesAutoresizingMaskIntoConstraints = false
  250. NSLayoutConstraint.activate([
  251. cameraView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20.0),
  252. cameraView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10.0),
  253. cameraView.widthAnchor.constraint(equalToConstant: 120.0),
  254. cameraView.heightAnchor.constraint(equalToConstant: 160.0)
  255. ])
  256. cameraView.backgroundColor = .secondaryColor
  257. cameraView.makeRoundedView(radius: 8)
  258. }
  259. func addListRemoteView() {
  260. view.addSubview(scrollRemoteView)
  261. scrollRemoteView.translatesAutoresizingMaskIntoConstraints = false
  262. NSLayoutConstraint.activate([
  263. scrollRemoteView.topAnchor.constraint(equalTo: cameraView.bottomAnchor, constant: 10),
  264. scrollRemoteView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10),
  265. scrollRemoteView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
  266. scrollRemoteView.widthAnchor.constraint(equalToConstant: 120.0)
  267. ])
  268. scrollRemoteView.showsHorizontalScrollIndicator = false
  269. scrollRemoteView.showsVerticalScrollIndicator = false
  270. scrollRemoteView.contentSize.width = 120.0
  271. scrollRemoteView.backgroundColor = .clear
  272. }
  273. func addBackgroundIncoming() {
  274. view.addSubview(myImage)
  275. myImage.translatesAutoresizingMaskIntoConstraints = false
  276. NSLayoutConstraint.activate([
  277. myImage.topAnchor.constraint(equalTo: view.topAnchor),
  278. myImage.bottomAnchor.constraint(equalTo: view.bottomAnchor),
  279. myImage.leadingAnchor.constraint(equalTo: view.leadingAnchor),
  280. myImage.trailingAnchor.constraint(equalTo: view.trailingAnchor),
  281. ])
  282. myImage.backgroundColor = .lightGray
  283. myImage.tintColor = .secondaryColor
  284. let image = dataPerson[0]["picture"]!!
  285. if image.isEmpty {
  286. myImage.image = UIImage(systemName: "person")
  287. myImage.contentMode = .scaleAspectFit
  288. } else {
  289. myImage.setImage(name: image)
  290. myImage.contentMode = .scaleAspectFill
  291. }
  292. // let idMe = UserDefaults.standard.string(forKey: "me") as String?
  293. // Database().database?.inTransaction({ fmdb, rollback in
  294. // if let c = Database().getRecords(fmdb: fmdb, query: "select image_id from BUDDY where f_pin = '\(idMe!)'"), c.next() {
  295. // let image = c.string(forColumnIndex: 0)!
  296. // if image.isEmpty {
  297. // myImage.image = UIImage(systemName: "person")
  298. // myImage.contentMode = .scaleAspectFit
  299. // } else {
  300. // myImage.setImage(name: image)
  301. // myImage.contentMode = .scaleAspectFill
  302. // }
  303. // c.close()
  304. // }
  305. // })
  306. }
  307. func addProfileNameCalling() {
  308. view.addSubview(profileImage)
  309. profileImage.translatesAutoresizingMaskIntoConstraints = false
  310. profileImage.frame.size = CGSize(width: 60.0, height: 60.0)
  311. NSLayoutConstraint.activate([
  312. profileImage.topAnchor.constraint(equalTo: view.topAnchor, constant: 40.0),
  313. profileImage.centerXAnchor.constraint(equalTo: view.centerXAnchor),
  314. profileImage.widthAnchor.constraint(equalToConstant: 60.0),
  315. profileImage.heightAnchor.constraint(equalToConstant: 63.0)
  316. ])
  317. profileImage.backgroundColor = .lightGray
  318. profileImage.tintColor = .secondaryColor
  319. profileImage.circle()
  320. let image = dataPerson[0]["picture"]!!
  321. if image.isEmpty {
  322. profileImage.image = UIImage(systemName: "person")
  323. profileImage.contentMode = .scaleAspectFit
  324. profileImage.layer.borderWidth = 1
  325. profileImage.layer.borderColor = UIColor.secondaryColor.cgColor
  326. } else {
  327. profileImage.setImage(name: image)
  328. profileImage.contentMode = .scaleAspectFill
  329. }
  330. view.addSubview(name)
  331. name.translatesAutoresizingMaskIntoConstraints = false
  332. NSLayoutConstraint.activate([
  333. name.topAnchor.constraint(equalTo: profileImage.bottomAnchor, constant: 5.0),
  334. name.centerXAnchor.constraint(equalTo: view.centerXAnchor)
  335. ])
  336. name.font = UIFont.systemFont(ofSize: 12)
  337. name.backgroundColor = .black.withAlphaComponent(0.05)
  338. name.layer.cornerRadius = 5.0
  339. name.clipsToBounds = true
  340. name.textColor = .mainColor
  341. name.text = dataPerson[0]["name"]!?.trimmingCharacters(in: .whitespaces)
  342. }
  343. func Calling() {
  344. view.addSubview(labelIncomingOutgoing)
  345. labelIncomingOutgoing.translatesAutoresizingMaskIntoConstraints = false
  346. NSLayoutConstraint.activate([
  347. labelIncomingOutgoing.topAnchor.constraint(equalTo: name.bottomAnchor, constant: 40.0),
  348. labelIncomingOutgoing.centerXAnchor.constraint(equalTo: view.centerXAnchor)
  349. ])
  350. if isInisiator {
  351. labelIncomingOutgoing.text = "Outgoing video call".localized() + "..."
  352. // Nexilis.startAudio()
  353. if ticketId.isEmpty {
  354. if callFCM {
  355. DispatchQueue.global().async {
  356. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getCalling(fPin: self.dataPerson[0]["f_pin"]!!, type: "2"), timeout: 30 * 1000) {
  357. if response.isOk() {
  358. } else {
  359. DispatchQueue.main.async {
  360. if self.labelIncomingOutgoing.isDescendant(of: self.view) {
  361. self.labelIncomingOutgoing.text = "Busy".localized()
  362. }
  363. if self.buttonDecline.isDescendant(of: self.view) {
  364. self.buttonDecline.removeFromSuperview()
  365. }
  366. if self.buttonAccept.isDescendant(of: self.view) {
  367. self.buttonAccept.removeFromSuperview()
  368. }
  369. }
  370. }
  371. } else {
  372. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  373. imageView.tintColor = .white
  374. let banner = FloatingNotificationBanner(title: "Unable to access servers. Try again later".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
  375. banner.show()
  376. }
  377. }
  378. } else {
  379. Nexilis.ringtonePlayer?.play()
  380. API.initiateCCall(sParty: dataPerson[0]["f_pin"]!, nCamIdx: 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViewFix, ivLocalView: cameraView, ivRemoteZ: zoomView)
  381. }
  382. } else {
  383. API.ccs(sTicketID: ticketId, nCamIdx: 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViewFix, ivLocalView: cameraView, ivRemoteZ: zoomView, bCameraOn: true)
  384. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getIncomingCallCS(f_pin_opposite: users[0].pin), timeout: 30 * 1000){
  385. if response.mBodies[CoreMessage_TMessageKey.ERRCOD] != "01" {
  386. endAllCall()
  387. }
  388. }
  389. }
  390. } else {
  391. let systemSoundID: SystemSoundID = 1254
  392. AudioServicesPlaySystemSound(systemSoundID)
  393. labelIncomingOutgoing.text = "Incoming video call".localized() + "..."
  394. }
  395. labelIncomingOutgoing.font = UIFont.systemFont(ofSize: 12)
  396. labelIncomingOutgoing.backgroundColor = .black.withAlphaComponent(0.05)
  397. labelIncomingOutgoing.layer.cornerRadius = 5.0
  398. labelIncomingOutgoing.clipsToBounds = true
  399. labelIncomingOutgoing.textColor = .mainColor
  400. }
  401. func addToolbar() {
  402. view.addSubview(buttonDecline)
  403. buttonDecline.translatesAutoresizingMaskIntoConstraints = false
  404. buttonDecline.frame.size = CGSize(width: 70.0, height: 70.0)
  405. if isInisiator {
  406. constraintLeadingButtonDecline = buttonDecline.centerXAnchor.constraint(equalTo: view.centerXAnchor)
  407. } else {
  408. constraintLeadingButtonDecline = buttonDecline.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: view.frame.width * 0.2)
  409. }
  410. constraintBottomButtonDecline = buttonDecline.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -60.0)
  411. NSLayoutConstraint.activate([
  412. constraintBottomButtonDecline,
  413. constraintLeadingButtonDecline,
  414. buttonDecline.widthAnchor.constraint(equalToConstant: 70.0),
  415. buttonDecline.heightAnchor.constraint(equalToConstant: 70.0)
  416. ])
  417. buttonDecline.backgroundColor = .red
  418. buttonDecline.circle()
  419. buttonDecline.setImage(UIImage(systemName: "xmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
  420. buttonDecline.tintColor = .white
  421. buttonDecline.addTarget(self, action: #selector(didTapDeclineCallButton(sender:)), for: .touchUpInside)
  422. if !isInisiator{
  423. view.addSubview(buttonAccept)
  424. buttonAccept.translatesAutoresizingMaskIntoConstraints = false
  425. buttonAccept.frame.size = CGSize(width: 70.0, height: 70.0)
  426. NSLayoutConstraint.activate([
  427. buttonAccept.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -60.0),
  428. buttonAccept.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -(view.frame.width * 0.2)),
  429. buttonAccept.widthAnchor.constraint(equalToConstant: 70.0),
  430. buttonAccept.heightAnchor.constraint(equalToConstant: 70.0)
  431. ])
  432. buttonAccept.backgroundColor = .greenColor
  433. buttonAccept.circle()
  434. buttonAccept.setImage(UIImage(systemName: "checkmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
  435. buttonAccept.tintColor = .white
  436. buttonAccept.addTarget(self, action: #selector(didTapAcceptCallButton), for: .touchUpInside)
  437. }
  438. }
  439. @objc func onCallFCM(notification: NSNotification) {
  440. DispatchQueue.main.async { [self] in
  441. let data:[AnyHashable : Any] = notification.userInfo!
  442. if let l_pin = data["l_pin"] as? String {
  443. Nexilis.ringtonePlayer?.play()
  444. API.initiateCCall(sParty: l_pin, nCamIdx: 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViewFix, ivLocalView: cameraView, ivRemoteZ: zoomView)
  445. }
  446. }
  447. }
  448. @objc func onReceiveMessage(notification: NSNotification) {
  449. DispatchQueue.main.async {
  450. let data:[AnyHashable : Any] = notification.userInfo!
  451. if let dataMessage = data["message"] as? TMessage {
  452. if (dataMessage.getCode() == CoreMessage_TMessageCode.PUSH_MEMBER_ROOM_CONTACT_CENTER) {
  453. let data = dataMessage.getBody(key: CoreMessage_TMessageKey.DATA)
  454. if !data.isEmpty {
  455. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  456. var members = ""
  457. let idMe = UserDefaults.standard.string(forKey: "me")!
  458. for json in jsonArray {
  459. if "\(json)" != idMe {
  460. if members.isEmpty {
  461. members = "\(json)"
  462. } else {
  463. members += ",\(json)"
  464. }
  465. }
  466. }
  467. UserDefaults.standard.set("\(members)", forKey: "membersCC")
  468. }
  469. }
  470. }
  471. }
  472. }
  473. }
  474. @objc func didTapDeclineCallButton(sender: AnyObject){
  475. let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
  476. if !onGoingCC.isEmpty {
  477. let alert = LibAlertController(title: "Interaction with Call Center is in progress".localized(), message: "Are you sure you want to end the Call Center?".localized(), preferredStyle: .alert)
  478. alert.addAction(UIAlertAction(title: "No".localized(), style: UIAlertAction.Style.default, handler: nil))
  479. alert.addAction(UIAlertAction(title: "Yes".localized(), style: UIAlertAction.Style.default, handler: {(_) in
  480. if(!self.wbRoomId.isEmpty){
  481. DispatchQueue.main.async {
  482. self.wbTimer.invalidate()
  483. _ = Nexilis.getWhiteboardDelegate()?.terminate()
  484. }
  485. }
  486. self.endAllCall()
  487. self.dismiss(animated: true, completion: nil)
  488. }))
  489. self.present(alert, animated: true, completion: nil)
  490. } else {
  491. let alert = LibAlertController(title: "End Video Call".localized(), message: "Are you sure you want to end video call?".localized(), preferredStyle: .alert)
  492. alert.addAction(UIAlertAction(title: "No".localized(), style: UIAlertAction.Style.default, handler: nil))
  493. alert.addAction(UIAlertAction(title: "Yes".localized(), style: UIAlertAction.Style.default, handler: {(_) in
  494. if self.labelIncomingOutgoing.isDescendant(of: self.view) {
  495. self.labelIncomingOutgoing.text = "Video call is over".localized()
  496. }
  497. if self.stackViewToolbar.isDescendant(of: self.view){
  498. self.stackViewToolbar.removeFromSuperview()
  499. }
  500. if self.stackViewToolbar2.isDescendant(of: self.view){
  501. self.stackViewToolbar2.removeFromSuperview()
  502. }
  503. if self.buttonWB.isDescendant(of: self.view){
  504. self.buttonWB.removeFromSuperview()
  505. }
  506. if self.buttonChat.isDescendant(of: self.view){
  507. self.buttonChat.removeFromSuperview()
  508. }
  509. if self.buttonDecline.isDescendant(of: self.view) {
  510. self.buttonDecline.removeFromSuperview()
  511. }
  512. if self.buttonAccept.isDescendant(of: self.view) {
  513. self.buttonAccept.removeFromSuperview()
  514. }
  515. if self.buttonRotate.isDescendant(of: self.view) {
  516. self.buttonRotate.removeFromSuperview()
  517. }
  518. if self.wbVC != nil{
  519. self.wbVC!.close?()
  520. }
  521. self.wbTimer.invalidate()
  522. self.vcTimer.invalidate()
  523. self.labelTimerVC.text = "Video call is over".localized()
  524. self.endAllCall()
  525. DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
  526. if self.isInisiator && !self.isPresent {
  527. self.navigationController?.popViewController(animated: true)
  528. } else {
  529. self.dismiss(animated: true, completion: nil)
  530. }
  531. }
  532. }))
  533. self.present(alert, animated: true, completion: nil)
  534. }
  535. }
  536. @objc func didTapAcceptCallButton() {
  537. if !isInisiator{
  538. let goAudioCall = Nexilis.checkMicPermission()
  539. let goVideoCall = Nexilis.checkCameraPermission()
  540. if goVideoCall == 0 {
  541. let alert = LibAlertController(title: "Attention!".localized(), message: !goAudioCall && goVideoCall == 0 ? "Please allow microphone & camera permission in your settings".localized() : !goAudioCall ? "Please allow microphone permission in your settings".localized() : "Please allow camera permission in your settings", preferredStyle: .alert)
  542. alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: {_ in
  543. if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
  544. UIApplication.shared.open(url, options: [:], completionHandler: nil)
  545. }
  546. }))
  547. self.navigationController?.present(alert, animated: true, completion: nil)
  548. return
  549. } else if goVideoCall == -1 {
  550. return
  551. }
  552. // Nexilis.startAudio()
  553. if ticketId.isEmpty {
  554. API.receiveCCall(sParty: dataPerson[0]["f_pin"]!, nCamIdx: 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViewFix, ivLocalView: cameraView,ivRemoteZ: zoomView)
  555. } else {
  556. API.csa(sTicketID: ticketId, nCamIdx: 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViewFix, ivLocalView: cameraView, ivRemoteZ: zoomView, bCameraOn: true)
  557. }
  558. }
  559. DispatchQueue.main.async {
  560. self.myImage.removeFromSuperview()
  561. self.name.removeFromSuperview()
  562. self.profileImage.removeFromSuperview()
  563. self.labelIncomingOutgoing.removeFromSuperview()
  564. self.buttonAccept.removeFromSuperview()
  565. NSLayoutConstraint.deactivate([
  566. self.constraintLeadingButtonDecline,
  567. self.constraintBottomButtonDecline
  568. ])
  569. self.addToolbarAfterAccept()
  570. self.buttonDecline.setImage(UIImage(systemName: "phone.down", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
  571. UIView.animate(withDuration: 1.0, animations: {
  572. self.view.layoutIfNeeded()
  573. })
  574. DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
  575. self.containerTimerVC.isHidden = false
  576. self.buttonRotate.isHidden = false
  577. self.buttonAddParticipant.isHidden = false
  578. self.buttonSpeaker.isHidden = false
  579. self.buttonWB.isHidden = false
  580. self.buttonChat.isHidden = false
  581. self.poweredByView.isHidden = false
  582. let connectDate = Date()
  583. self.vcTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
  584. let format = Utils.callDurationFormatter.string(from: Date().timeIntervalSince(connectDate))
  585. self.labelTimerVC.text = format
  586. }
  587. self.vcTimer.fire()
  588. API.adjustVolume(fValue: 10.0)
  589. }
  590. }
  591. }
  592. @objc func didTapChatButton(){
  593. let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
  594. let members = UserDefaults.standard.string(forKey: "membersCC") ?? ""
  595. let officer = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[1]
  596. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  597. editorPersonalVC.hidesBottomBarWhenPushed = true
  598. editorPersonalVC.unique_l_pin = officer
  599. editorPersonalVC.fromNotification = true
  600. editorPersonalVC.isContactCenter = true
  601. editorPersonalVC.fPinContacCenter = members
  602. editorPersonalVC.complaintId = ticketId
  603. editorPersonalVC.onGoingCC = true
  604. editorPersonalVC.isRequestContactCenter = false
  605. editorPersonalVC.users = users
  606. editorPersonalVC.fromVCAC = true
  607. let navigationController = CustomNavigationController(rootViewController: editorPersonalVC)
  608. navigationController.modalPresentationStyle = .overCurrentContext
  609. navigationController.navigationBar.tintColor = .white
  610. navigationController.navigationBar.barTintColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  611. navigationController.navigationBar.isTranslucent = false
  612. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  613. navigationController.navigationBar.barStyle = .black
  614. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  615. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  616. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  617. navigationController.navigationBar.titleTextAttributes = textAttributes
  618. if UIApplication.shared.visibleViewController?.navigationController != nil {
  619. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  620. } else {
  621. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  622. }
  623. }
  624. @objc func didTapWBButton(){
  625. if(wbVC == nil){
  626. wbVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "wbVC") as? WhiteboardViewController
  627. if(wbRoomId.isEmpty){
  628. let me = UserDefaults.standard.string(forKey: "me")!
  629. let tid = CoreMessage_TMessageUtil.getTID()
  630. wbRoomId = "\(me)wbvc\(tid)"
  631. wbVC!.roomId = wbRoomId
  632. var destinations = [String]()
  633. var destString = ""
  634. for d in dataPerson{
  635. destinations.append(d["f_pin"]!!)
  636. if destString.isEmpty{
  637. destString = d["f_pin"]!!
  638. } else {
  639. destString = destString + ",\(d["f_pin"]!!)"
  640. }
  641. }
  642. wbVC!.destinations = destinations
  643. wbVC!.sendInit()
  644. UserDefaults.standard.set("\(me),\(destString)", forKey: "wb_vc")
  645. }
  646. else {
  647. self.wbTimer.invalidate()
  648. self.buttonWB.backgroundColor = .lightGray
  649. wbVC!.roomId = wbRoomId
  650. wbVC!.sendJoin()
  651. }
  652. }
  653. wbVC!.close = {
  654. DispatchQueue.main.async {
  655. if self.wbVC!.view.isDescendant(of: self.view){
  656. self.wbVC!.view.removeFromSuperview()
  657. }
  658. self.buttonDecline.isHidden = false
  659. self.buttonSpeaker.isHidden = false
  660. self.buttonAddParticipant.isHidden = false
  661. self.buttonRotate.isHidden = false
  662. // if(!self.wbRoomId.isEmpty){
  663. // DispatchQueue.main.async {
  664. // self.wbTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.runTimer), userInfo: nil, repeats: true)
  665. // }
  666. // }
  667. }
  668. }
  669. self.buttonDecline.isHidden = true
  670. self.buttonSpeaker.isHidden = true
  671. self.buttonAddParticipant.isHidden = true
  672. self.buttonRotate.isHidden = true
  673. addChild(wbVC!)
  674. wbVC!.view.translatesAutoresizingMaskIntoConstraints = false
  675. view.addSubview(wbVC!.view)
  676. onScreenConstraintWB = [
  677. wbVC!.view.topAnchor.constraint(equalTo: self.view.topAnchor),
  678. wbVC!.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
  679. wbVC!.view.rightAnchor.constraint(equalTo: self.view.rightAnchor),
  680. wbVC!.view.leftAnchor.constraint(equalTo: self.view.leftAnchor),
  681. ]
  682. NSLayoutConstraint.activate(onScreenConstraintWB)
  683. // Notify the child view controller that the move is complete.
  684. wbVC!.didMove(toParent: self)
  685. // self.navigationController?.setNavigationBarHidden(false, animated: true)
  686. // controller.modalPresentationStyle = .overCurrentContext
  687. // self.navigationController?.present(controller, animated: true)
  688. }
  689. func addToolbarAfterAccept() {
  690. self.view.addSubview(self.stackViewToolbar)
  691. self.stackViewToolbar.translatesAutoresizingMaskIntoConstraints = false
  692. constraintBottomStackViewToolbar = self.stackViewToolbar.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -60.0)
  693. NSLayoutConstraint.activate([
  694. self.stackViewToolbar.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
  695. constraintBottomStackViewToolbar
  696. ])
  697. self.stackViewToolbar.axis = .horizontal
  698. self.stackViewToolbar.distribution = .equalSpacing
  699. self.stackViewToolbar.alignment = .center
  700. self.stackViewToolbar.spacing = 30
  701. self.view.addSubview(buttonRotate)
  702. buttonRotate.translatesAutoresizingMaskIntoConstraints = false
  703. buttonRotate.frame.size = CGSize(width: 70.0, height: 70.0)
  704. NSLayoutConstraint.activate([
  705. buttonRotate.widthAnchor.constraint(equalToConstant: 70.0),
  706. buttonRotate.heightAnchor.constraint(equalToConstant: 70.0),
  707. buttonRotate.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
  708. buttonRotate.bottomAnchor.constraint(equalTo: self.stackViewToolbar.topAnchor, constant: -10.0)
  709. ])
  710. buttonRotate.backgroundColor = .secondaryColor
  711. buttonRotate.setImage(UIImage(systemName: "arrow.triangle.2.circlepath.camera", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
  712. buttonRotate.tintColor = .mainColor
  713. buttonRotate.circle()
  714. buttonRotate.isHidden = true
  715. buttonRotate.addTarget(self, action: #selector(camera(sender:)), for: .touchUpInside)
  716. view.addSubview(buttonAddParticipant)
  717. buttonAddParticipant.translatesAutoresizingMaskIntoConstraints = false
  718. buttonAddParticipant.frame.size = CGSize(width: 70.0, height: 70.0)
  719. NSLayoutConstraint.activate([
  720. buttonAddParticipant.widthAnchor.constraint(equalToConstant: 70.0),
  721. buttonAddParticipant.heightAnchor.constraint(equalToConstant: 70.0)
  722. ])
  723. buttonAddParticipant.backgroundColor = .secondaryColor
  724. buttonAddParticipant.setImage(UIImage(systemName: "person.badge.plus", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
  725. buttonAddParticipant.tintColor = .mainColor
  726. buttonAddParticipant.circle()
  727. buttonAddParticipant.isHidden = true
  728. buttonAddParticipant.addTarget(self, action: #selector(didTapAddParticipantButton(sender:)), for: .touchUpInside)
  729. view.addSubview(buttonSpeaker)
  730. buttonSpeaker.translatesAutoresizingMaskIntoConstraints = false
  731. buttonSpeaker.frame.size = CGSize(width: 70.0, height: 70.0)
  732. NSLayoutConstraint.activate([
  733. buttonSpeaker.widthAnchor.constraint(equalToConstant: 70.0),
  734. buttonSpeaker.heightAnchor.constraint(equalToConstant: 70.0)
  735. ])
  736. buttonSpeaker.setImage(UIImage(systemName: "speaker.wave.2", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
  737. self.buttonSpeaker.backgroundColor = .lightGray
  738. self.buttonSpeaker.tintColor = .mainColor
  739. buttonSpeaker.circle()
  740. buttonSpeaker.isHidden = true
  741. buttonSpeaker.addTarget(self, action: #selector(didTapSpeakerButton(sender:)), for: .touchUpInside)
  742. self.view.addSubview(self.stackViewToolbar2)
  743. self.stackViewToolbar2.translatesAutoresizingMaskIntoConstraints = false
  744. constraintLeftStackViewToolbar2 = self.stackViewToolbar2.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 10.0)
  745. NSLayoutConstraint.activate([
  746. self.stackViewToolbar2.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
  747. constraintLeftStackViewToolbar2
  748. ])
  749. self.stackViewToolbar2.axis = .vertical
  750. self.stackViewToolbar2.distribution = .equalSpacing
  751. self.stackViewToolbar2.alignment = .center
  752. self.stackViewToolbar2.spacing = 5
  753. view.addSubview(buttonWB)
  754. buttonWB.translatesAutoresizingMaskIntoConstraints = false
  755. buttonWB.frame.size = CGSize(width: 40.0, height: 40.0)
  756. NSLayoutConstraint.activate([
  757. buttonWB.widthAnchor.constraint(equalToConstant: 40.0),
  758. buttonWB.heightAnchor.constraint(equalToConstant: 40.0)
  759. ])
  760. buttonWB.backgroundColor = .lightGray
  761. buttonWB.setImage(UIImage(systemName: "ipad.landscape", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .medium, scale: .default)), for: .normal)
  762. buttonWB.circle()
  763. buttonWB.tintColor = .black
  764. buttonWB.isHidden = true
  765. buttonWB.addTarget(self, action: #selector(didTapWBButton), for: .touchUpInside)
  766. if !ticketId.isEmpty {
  767. view.addSubview(buttonChat)
  768. buttonChat.translatesAutoresizingMaskIntoConstraints = false
  769. buttonChat.frame.size = CGSize(width: 40.0, height: 40.0)
  770. NSLayoutConstraint.activate([
  771. buttonChat.widthAnchor.constraint(equalToConstant: 40.0),
  772. buttonChat.heightAnchor.constraint(equalToConstant: 40.0)
  773. ])
  774. buttonChat.backgroundColor = .lightGray
  775. buttonChat.setImage(UIImage(systemName: "bubble.right", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .medium, scale: .default)), for: .normal)
  776. buttonChat.circle()
  777. buttonChat.tintColor = .black
  778. buttonChat.isHidden = true
  779. buttonChat.addTarget(self, action: #selector(didTapChatButton), for: .touchUpInside)
  780. }
  781. self.view.addSubview(poweredByView)
  782. self.poweredByView.translatesAutoresizingMaskIntoConstraints = false
  783. let constraintRightPowered = self.poweredByView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -10.0)
  784. let constraintBottomPowered = self.poweredByView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -10.0)
  785. NSLayoutConstraint.activate([
  786. constraintRightPowered,
  787. constraintBottomPowered,
  788. nexilisLogo.widthAnchor.constraint(equalToConstant: 30.0),
  789. nexilisLogo.heightAnchor.constraint(equalToConstant: 30.0)
  790. ])
  791. poweredByView.addArrangedSubview(poweredByLabel)
  792. poweredByView.addArrangedSubview(nexilisLogo)
  793. poweredByView.isHidden = true
  794. stackViewToolbar.addArrangedSubview(buttonAddParticipant)
  795. stackViewToolbar.addArrangedSubview(buttonDecline)
  796. stackViewToolbar.addArrangedSubview(buttonSpeaker)
  797. stackViewToolbar2.addArrangedSubview(buttonWB)
  798. stackViewToolbar2.addArrangedSubview(buttonChat)
  799. // startFaceTimer()
  800. }
  801. func endAllCall() {
  802. if isInisiator {
  803. Nexilis.ringbacktonePlayer?.stop()
  804. } else {
  805. Nexilis.ringtonePlayer?.stop()
  806. }
  807. let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
  808. if !onGoingCC.isEmpty {
  809. let requester = onGoingCC.components(separatedBy: ",")[0]
  810. let officer = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[1]
  811. let complaintId = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[2]
  812. let idMe = UserDefaults.standard.string(forKey: "me")!
  813. let startTimeCC = UserDefaults.standard.string(forKey: "startTimeCC") ?? ""
  814. DispatchQueue.global().async {
  815. let date = "\(Date().currentTimeMillis())"
  816. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  817. do {
  818. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "CALL_CENTER_HISTORY", cvalues: [
  819. "type" : "2",
  820. "title" : "Contact Center".localized(),
  821. "time" : startTimeCC,
  822. "f_pin" : officer,
  823. "data" : complaintId,
  824. "time_end" : date,
  825. "complaint_id" : complaintId,
  826. "members" : "",
  827. "requester": requester
  828. ], replace: true)
  829. } catch {
  830. rollback.pointee = true
  831. //print(error)
  832. }
  833. })
  834. if officer == idMe {
  835. _ = Nexilis.write(message: CoreMessage_TMessageBank.endCallCenter(complaint_id: complaintId, l_pin: requester))
  836. } else {
  837. if requester == idMe {
  838. _ = Nexilis.write(message: CoreMessage_TMessageBank.endCallCenter(complaint_id: complaintId, l_pin: officer))
  839. } else {
  840. _ = Nexilis.write(message: CoreMessage_TMessageBank.leaveCCRoomInvite(ticket_id: complaintId))
  841. }
  842. }
  843. UserDefaults.standard.removeObject(forKey: "onGoingCC")
  844. UserDefaults.standard.removeObject(forKey: "membersCC")
  845. UserDefaults.standard.removeObject(forKey: "startTimeCC")
  846. UserDefaults.standard.removeObject(forKey: "waitingRequestCC")
  847. }
  848. }
  849. API.terminateCall(sParty: nil)
  850. cameraView.image = nil
  851. zoomView.image = nil
  852. listRemoteViewFix.removeAll()
  853. dataPerson.removeAll()
  854. }
  855. func setSpeaker(isSpeaker: Bool) {
  856. DispatchQueue.main.async {
  857. if (isSpeaker) {
  858. self.buttonSpeaker.backgroundColor = .lightGray
  859. self.buttonSpeaker.tintColor = .mainColor
  860. self.buttonSpeaker.setImage(UIImage(systemName: "speaker.wave.2", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
  861. } else {
  862. self.buttonSpeaker.backgroundColor = .secondaryColor
  863. self.buttonSpeaker.tintColor = .mainColor
  864. self.buttonSpeaker.setImage(UIImage(systemName: "speaker.slash", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
  865. }
  866. self.isSpeaker = isSpeaker
  867. }
  868. Nexilis.setSpeaker(isSpeaker, isVideo: true)
  869. }
  870. @objc func didTapSpeakerButton(sender: AnyObject){
  871. setSpeaker(isSpeaker: !(self.isSpeaker))
  872. }
  873. @objc func didTapAddParticipantButton(sender: AnyObject){
  874. if let contactViewController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID") as? ContactCallViewController {
  875. contactViewController.isAddParticipantVideo = true
  876. contactViewController.connectedCall = dataPerson
  877. contactViewController.isDismiss = { data in
  878. let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
  879. if !onGoingCC.isEmpty {
  880. DispatchQueue.global().async {
  881. _ = Nexilis.write(message: CoreMessage_TMessageBank.getCCRoomInvite(l_pin: data["f_pin"]!!, ticket_id: onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[2], channel: "2"))
  882. }
  883. DispatchQueue.main.async {
  884. self.isAddCall = data["f_pin"]!!
  885. }
  886. } else {
  887. DispatchQueue.main.async {
  888. self.dataPerson.append(data)
  889. API.initiateCCall(sParty: data["f_pin"]!, nCamIdx: 1, nResIdx: 2, nVQuality: 4, ivRemoteView: self.listRemoteViewFix, ivLocalView: self.cameraView, ivRemoteZ: self.zoomView)
  890. }
  891. }
  892. }
  893. present(CustomNavigationController(rootViewController: contactViewController), animated: true, completion: nil)
  894. }
  895. }
  896. @objc func camera(sender: Any?) {
  897. if frontCamera {
  898. API.changeCameraParam(nCameraIdx: 0, nResolutionIndex: 2, nQuality: 4)
  899. frontCamera = false
  900. } else {
  901. API.changeCameraParam(nCameraIdx: 1, nResolutionIndex: 2, nQuality: 4)
  902. frontCamera = true
  903. }
  904. }
  905. @objc func hideToolbar() {
  906. DispatchQueue.main.async {
  907. if self.showStackViewToolbar {
  908. self.showStackViewToolbar = false
  909. self.constraintBottomStackViewToolbar.constant = 150
  910. self.constraintLeftStackViewToolbar2.constant = -60
  911. UIView.animate(withDuration: 0.35, animations: {
  912. self.view.layoutIfNeeded()
  913. })
  914. } else {
  915. self.showStackViewToolbar = true
  916. self.constraintBottomStackViewToolbar.constant = -60
  917. self.constraintLeftStackViewToolbar2.constant = 10
  918. UIView.animate(withDuration: 0.35, animations: {
  919. self.view.layoutIfNeeded()
  920. })
  921. }
  922. }
  923. }
  924. @objc func onStatusCall(_ notification: NSNotification) {
  925. let data = notification.userInfo
  926. let state = (data?["state"] ?? 0) as! Int
  927. let message = (data?["message"] ?? "") as! String
  928. var remoteChannel = [String:String]()
  929. let arrayMessage = message.split(separator: ",")
  930. if(state == Nexilis.VIDEO_CALL_ZOOM){
  931. DispatchQueue.main.async {
  932. if self.dataPerson.count > 1 {
  933. if !self.transformZoomAfterNewUserMore2 {
  934. self.zoomView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi * 3)/2)
  935. self.transformZoomAfterNewUserMore2 = true
  936. }
  937. }
  938. }
  939. }
  940. else if (state == Nexilis.VIDEO_CAMERA_PARAMS_CHANED){
  941. if(arrayMessage[3] == "0"){
  942. DispatchQueue.main.async {
  943. if self.dataPerson.count == 1 && arrayMessage[2] == "1" && arrayMessage[4] == "1" {
  944. self.zoomView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi * 3)/2)
  945. } else {
  946. self.zoomView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi)/2)
  947. }
  948. }
  949. }
  950. }
  951. else if (state == Nexilis.VIDEO_CALL_OFFHOOK) {
  952. if isInisiator {
  953. Nexilis.ringbacktonePlayer?.stop()
  954. }
  955. let channel = arrayMessage[3]
  956. remoteChannel[String(channel)] = String(arrayMessage[5])
  957. DispatchQueue.main.async {
  958. if (self.dataPerson.count == 1 && String(arrayMessage[1]) != self.dataPerson[0]["f_pin"]!!) {
  959. self.getDataProfile(fPin: String(arrayMessage[1]))
  960. for i in 0...1 {
  961. self.scrollRemoteView.addSubview(self.listRemoteViewFix[i])
  962. self.listRemoteViewFix[i].frame = CGRect(x: 0, y: 170 * i, width: 120, height: 160)
  963. self.listRemoteViewFix[i].backgroundColor = .clear
  964. self.listRemoteViewFix[i].makeRoundedView(radius: 8.0)
  965. self.scrollRemoteView.addSubview(self.containerLabelName[i])
  966. self.containerLabelName[i].frame = CGRect(x: 0, y: 170 * i, width: 120, height: 30)
  967. self.containerLabelName[i].backgroundColor = .orangeBNI.withAlphaComponent(0.5)
  968. self.containerLabelName[i].makeRoundedView(radius: 8.0)
  969. if i == 0 {
  970. if self.dataPerson[0]["user_type"] == "2" {
  971. self.listRemoteViewFix[0].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.3).rotated(by: (CGFloat.pi)/2)
  972. } else {
  973. self.listRemoteViewFix[0].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.3).rotated(by: (CGFloat.pi * 3 )/2)
  974. }
  975. } else {
  976. if arrayMessage[5] == "2" {
  977. self.listRemoteViewFix[1].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.3).rotated(by: (CGFloat.pi)/2)
  978. } else {
  979. self.listRemoteViewFix[1].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.3).rotated(by: (CGFloat.pi * 3 )/2)
  980. }
  981. }
  982. let pictureImage = self.dataPerson[i]["picture"] ?? ""
  983. let namePerson = self.dataPerson[i]["name"] ?? ""
  984. if (!pictureImage!.isEmpty) {
  985. self.listRemoteViewFix[i].setImage(name: pictureImage!)
  986. self.listRemoteViewFix[i].contentMode = .scaleAspectFill
  987. } else {
  988. self.listRemoteViewFix[i].image = UIImage(systemName: "person")
  989. self.listRemoteViewFix[i].backgroundColor = UIColor.systemGray6
  990. self.listRemoteViewFix[i].contentMode = .scaleAspectFit
  991. }
  992. let labelName = UILabel()
  993. self.containerLabelName[i].addSubview(labelName)
  994. labelName.anchor(left: self.containerLabelName[i].leftAnchor, right: self.containerLabelName[i].rightAnchor, paddingLeft: 5, paddingRight: 5, centerX: self.containerLabelName[i].centerXAnchor, centerY: self.containerLabelName[i].centerYAnchor)
  995. labelName.text = namePerson
  996. labelName.textAlignment = .center
  997. labelName.textColor = .white
  998. }
  999. self.scrollRemoteView.contentSize.height = CGFloat(170 * 2)
  1000. } else if self.dataPerson.count > 1 {
  1001. if self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[1]}) != nil {
  1002. return
  1003. }
  1004. self.getDataProfile(fPin: String(arrayMessage[1]))
  1005. let i = self.dataPerson.count - 1
  1006. self.scrollRemoteView.addSubview(self.listRemoteViewFix[i])
  1007. self.listRemoteViewFix[i].frame = CGRect(x: 0, y: 170 * i, width: 120, height: 160)
  1008. self.listRemoteViewFix[i].backgroundColor = .clear
  1009. self.listRemoteViewFix[i].makeRoundedView(radius: 8.0)
  1010. self.scrollRemoteView.addSubview(self.containerLabelName[i])
  1011. self.containerLabelName[i].frame = CGRect(x: 0, y: 170 * i, width: 120, height: 30)
  1012. self.containerLabelName[i].backgroundColor = .orangeBNI.withAlphaComponent(0.5)
  1013. self.containerLabelName[i].makeRoundedView(radius: 8.0)
  1014. if arrayMessage[5] == "2" {
  1015. self.listRemoteViewFix[i].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.3).rotated(by: (CGFloat.pi)/2)
  1016. } else {
  1017. self.listRemoteViewFix[i].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.3).rotated(by: (CGFloat.pi * 3 )/2)
  1018. }
  1019. let pictureImage = self.dataPerson[self.dataPerson.count - 1]["picture"] ?? ""
  1020. let namePerson = self.dataPerson[self.dataPerson.count - 1]["name"] ?? ""
  1021. if (!pictureImage!.isEmpty) {
  1022. self.listRemoteViewFix[i].setImage(name: pictureImage!)
  1023. self.listRemoteViewFix[i].contentMode = .scaleAspectFill
  1024. } else {
  1025. self.listRemoteViewFix[i].image = UIImage(systemName: "person")
  1026. self.listRemoteViewFix[i].backgroundColor = UIColor.systemGray6
  1027. self.listRemoteViewFix[i].contentMode = .scaleAspectFit
  1028. }
  1029. self.scrollRemoteView.contentSize.height = CGFloat(170 * (i + 1))
  1030. let labelName = UILabel()
  1031. self.containerLabelName[i].addSubview(labelName)
  1032. labelName.anchor(left: self.containerLabelName[i].leftAnchor, right: self.containerLabelName[i].rightAnchor, paddingLeft: 5, paddingRight: 5, centerX: self.containerLabelName[i].centerXAnchor, centerY: self.containerLabelName[i].centerYAnchor)
  1033. labelName.text = namePerson
  1034. labelName.textAlignment = .center
  1035. labelName.textColor = .white
  1036. }
  1037. }
  1038. if arrayMessage[5] == "2" && self.dataPerson.count == 1 {
  1039. DispatchQueue.main.async {
  1040. self.zoomView.transform = CGAffineTransform.init(scaleX: -1.9, y: 1.9).rotated(by: (CGFloat.pi)/2)
  1041. self.zoomView.contentMode = .scaleAspectFit
  1042. }
  1043. }
  1044. else if self.dataPerson.count == 1 {
  1045. DispatchQueue.main.async {
  1046. self.zoomView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi * 3)/2)
  1047. self.zoomView.contentMode = .scaleAspectFit
  1048. }
  1049. } else if self.dataPerson.count > 1 {
  1050. DispatchQueue.main.async {
  1051. for i in 0..<self.dataPerson.count {
  1052. // self.listRemoteViewFix[i].image = self.listRemoteViewFix[i].image?.rotate(radians: (CGFloat.pi * 3 )/2)
  1053. self.listRemoteViewFix[i].image = nil
  1054. if self.dataPerson[i]["user_type"] == "2" || arrayMessage[5] == "2" {
  1055. self.listRemoteViewFix[i].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.3).rotated(by: (CGFloat.pi)/2)
  1056. } else {
  1057. self.listRemoteViewFix[i].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.3).rotated(by: (CGFloat.pi * 3 )/2)
  1058. }
  1059. }
  1060. }
  1061. }
  1062. DispatchQueue.main.async {
  1063. if self.isInisiator && self.name.isDescendant(of: self.view) {
  1064. self.didTapAcceptCallButton()
  1065. }
  1066. let indexPerson = self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[1]})
  1067. if indexPerson != nil {
  1068. self.dataPerson[indexPerson!]["user_type"] = String(arrayMessage[5])
  1069. }
  1070. }
  1071. } else if (state == Nexilis.VIDEO_CALL_END || state == Nexilis.AUDIO_CALL_END) {
  1072. if isInisiator {
  1073. Nexilis.ringbacktonePlayer?.stop()
  1074. } else {
  1075. Nexilis.ringtonePlayer?.stop()
  1076. }
  1077. let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
  1078. if !onGoingCC.isEmpty {
  1079. let requester = onGoingCC.components(separatedBy: ",")[0]
  1080. let officer = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[1]
  1081. if arrayMessage[0] == requester || arrayMessage[0] == officer {
  1082. DispatchQueue.main.async {
  1083. let controller = self.presentedViewController
  1084. if controller != nil {
  1085. controller!.dismiss(animated: true)
  1086. }
  1087. if !self.showNotifCCEnd{
  1088. let imageView = UIImageView(image: UIImage(systemName: "info.circle"))
  1089. imageView.tintColor = .white
  1090. let banner = FloatingNotificationBanner(title: "Call Center Session has ended".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .info, colors: nil, iconPosition: .center)
  1091. banner.show()
  1092. self.showNotifCCEnd = true
  1093. }
  1094. if self.stackViewToolbar.isDescendant(of: self.view){
  1095. self.stackViewToolbar.removeFromSuperview()
  1096. }
  1097. if self.stackViewToolbar2.isDescendant(of: self.view){
  1098. self.stackViewToolbar2.removeFromSuperview()
  1099. }
  1100. if self.buttonWB.isDescendant(of: self.view){
  1101. self.buttonWB.removeFromSuperview()
  1102. }
  1103. if self.buttonChat.isDescendant(of: self.view){
  1104. self.buttonChat.removeFromSuperview()
  1105. }
  1106. if self.buttonDecline.isDescendant(of: self.view) {
  1107. self.buttonDecline.removeFromSuperview()
  1108. }
  1109. if self.buttonAccept.isDescendant(of: self.view) {
  1110. self.buttonAccept.removeFromSuperview()
  1111. }
  1112. if self.buttonRotate.isDescendant(of: self.view) {
  1113. self.buttonRotate.removeFromSuperview()
  1114. }
  1115. if self.wbVC != nil{
  1116. self.wbVC!.close?()
  1117. }
  1118. self.wbTimer.invalidate()
  1119. _ = Nexilis.getWhiteboardDelegate()?.terminate()
  1120. }
  1121. DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
  1122. self.endAllCall()
  1123. self.dismiss(animated: true, completion: nil)
  1124. }
  1125. return
  1126. }
  1127. }
  1128. DispatchQueue.main.async {
  1129. if (self.dataPerson.count == 1) {
  1130. if self.labelIncomingOutgoing.isDescendant(of: self.view) {
  1131. self.labelIncomingOutgoing.text = "Video call is over".localized()
  1132. }
  1133. if self.stackViewToolbar.isDescendant(of: self.view){
  1134. self.stackViewToolbar.removeFromSuperview()
  1135. }
  1136. if self.stackViewToolbar2.isDescendant(of: self.view){
  1137. self.stackViewToolbar2.removeFromSuperview()
  1138. }
  1139. if self.buttonWB.isDescendant(of: self.view){
  1140. self.buttonWB.removeFromSuperview()
  1141. }
  1142. if self.buttonChat.isDescendant(of: self.view){
  1143. self.buttonChat.removeFromSuperview()
  1144. }
  1145. if self.buttonDecline.isDescendant(of: self.view) {
  1146. self.buttonDecline.removeFromSuperview()
  1147. }
  1148. if self.buttonAccept.isDescendant(of: self.view) {
  1149. self.buttonAccept.removeFromSuperview()
  1150. }
  1151. if self.buttonRotate.isDescendant(of: self.view) {
  1152. self.buttonRotate.removeFromSuperview()
  1153. }
  1154. if self.wbVC != nil{
  1155. self.wbVC!.close?()
  1156. }
  1157. self.wbTimer.invalidate()
  1158. self.vcTimer.invalidate()
  1159. self.labelTimerVC.text = "Video call is over".localized()
  1160. _ = Nexilis.getWhiteboardDelegate()?.terminate()
  1161. let controller = self.presentedViewController
  1162. if controller != nil {
  1163. controller!.dismiss(animated: true)
  1164. }
  1165. DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
  1166. self.endAllCall()
  1167. if self.isInisiator && !self.isPresent {
  1168. self.navigationController?.popViewController(animated: true)
  1169. } else {
  1170. self.dismiss(animated: true, completion: nil)
  1171. }
  1172. }
  1173. } else {
  1174. let indexPerson = self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[0]})
  1175. if indexPerson != nil {
  1176. if (self.dataPerson.count == 2) {
  1177. self.containerLabelName.forEach({ $0.subviews.forEach({ $0.removeFromSuperview() }) })
  1178. self.scrollRemoteView.subviews.forEach({ $0.removeFromSuperview() })
  1179. } else {
  1180. self.containerLabelName[indexPerson! + indexPerson!].subviews.forEach({ $0.removeFromSuperview() })
  1181. self.scrollRemoteView.subviews[indexPerson! + indexPerson!].removeFromSuperview()
  1182. self.containerLabelName[indexPerson! + indexPerson!].subviews.forEach({ $0.removeFromSuperview() })
  1183. self.scrollRemoteView.subviews[indexPerson! + indexPerson!].removeFromSuperview()
  1184. if indexPerson! + 1 <= self.listRemoteViewFix.count {
  1185. let iLoop = (self.listRemoteViewFix.count - 1) - (indexPerson! + 1)
  1186. if iLoop >= 0 {
  1187. for i in 0...iLoop {
  1188. let viewAfterRemote = self.listRemoteViewFix[(indexPerson! + i) + 1]
  1189. let viewAfterName = self.containerLabelName[(indexPerson! + i) + 1]
  1190. viewAfterRemote.frame.origin.y = viewAfterRemote.frame.origin.y - 170
  1191. viewAfterName.frame.origin.y = viewAfterName.frame.origin.y - 170
  1192. UIView.animate(withDuration: 0.35, animations: {
  1193. self.scrollRemoteView.layoutIfNeeded()
  1194. })
  1195. }
  1196. }
  1197. }
  1198. }
  1199. self.dataPerson.remove(at: indexPerson!)
  1200. }
  1201. if !onGoingCC.isEmpty {
  1202. if let pin = arrayMessage.first, let index = self.users.firstIndex(of: User(pin: String(pin))) {
  1203. self.users.remove(at: index)
  1204. }
  1205. }
  1206. if self.dataPerson.count == 1 {
  1207. self.transformZoomAfterNewUserMore2 = false
  1208. self.zoomView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi)/2)
  1209. }
  1210. }
  1211. }
  1212. } else if (state == Nexilis.OFFLINE) {
  1213. if isInisiator {
  1214. Nexilis.ringbacktonePlayer?.stop()
  1215. } else {
  1216. Nexilis.ringtonePlayer?.stop()
  1217. }
  1218. let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
  1219. DispatchQueue.main.async {
  1220. if (self.dataPerson.count == 1) {
  1221. if self.labelIncomingOutgoing.isDescendant(of: self.view) {
  1222. self.labelIncomingOutgoing.text = "Offline".localized()
  1223. }
  1224. if self.buttonDecline.isDescendant(of: self.view) {
  1225. self.buttonDecline.removeFromSuperview()
  1226. }
  1227. if self.buttonAccept.isDescendant(of: self.view) {
  1228. self.buttonAccept.removeFromSuperview()
  1229. }
  1230. } else {
  1231. let indexPerson = self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[0]})
  1232. if indexPerson != nil {
  1233. if (self.dataPerson.count == 2) {
  1234. self.containerLabelName.forEach({ $0.subviews.forEach({ $0.removeFromSuperview() }) })
  1235. self.scrollRemoteView.subviews.forEach({ $0.removeFromSuperview() })
  1236. } else {
  1237. self.containerLabelName[indexPerson! + indexPerson!].subviews.forEach({ $0.removeFromSuperview() })
  1238. self.scrollRemoteView.subviews[indexPerson! + indexPerson!].removeFromSuperview()
  1239. self.containerLabelName[indexPerson! + indexPerson!].subviews.forEach({ $0.removeFromSuperview() })
  1240. self.scrollRemoteView.subviews[indexPerson! + indexPerson!].removeFromSuperview()
  1241. if indexPerson! + 1 <= self.listRemoteViewFix.count {
  1242. let viewAfterRemote = self.listRemoteViewFix[indexPerson! + 1]
  1243. let viewAfterName = self.containerLabelName[indexPerson! + 1]
  1244. viewAfterRemote.frame.origin.y = viewAfterRemote.frame.origin.y - 170
  1245. viewAfterName.frame.origin.y = viewAfterName.frame.origin.y - 170
  1246. UIView.animate(withDuration: 0.35, animations: {
  1247. self.scrollRemoteView.layoutIfNeeded()
  1248. })
  1249. }
  1250. }
  1251. }
  1252. if !onGoingCC.isEmpty {
  1253. if let pin = arrayMessage.first, let index = self.users.firstIndex(of: User(pin: String(pin))) {
  1254. self.users.remove(at: index)
  1255. if !onGoingCC.isEmpty && self.users.count != 0 {
  1256. DispatchQueue.main.async {
  1257. var members = ""
  1258. for user in self.users {
  1259. if members.isEmpty {
  1260. members = "\(user.pin)"
  1261. } else {
  1262. members = ",\(user.pin)"
  1263. }
  1264. }
  1265. UserDefaults.standard.set("\(members)", forKey: "membersCC")
  1266. }
  1267. }
  1268. }
  1269. }
  1270. self.dataPerson.remove(at: indexPerson!)
  1271. }
  1272. }
  1273. if (self.dataPerson.count == 1) {
  1274. DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
  1275. self.endAllCall()
  1276. if self.isInisiator && onGoingCC.isEmpty && !self.isPresent {
  1277. self.navigationController?.popViewController(animated: true)
  1278. } else {
  1279. self.dismiss(animated: true, completion: nil)
  1280. }
  1281. }
  1282. }
  1283. } else if (state == Nexilis.BUSY) {
  1284. if isInisiator {
  1285. Nexilis.ringbacktonePlayer?.stop()
  1286. } else {
  1287. Nexilis.ringtonePlayer?.stop()
  1288. }
  1289. let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
  1290. DispatchQueue.main.async { [self] in
  1291. if (self.dataPerson.count == 1) {
  1292. if self.labelIncomingOutgoing.isDescendant(of: self.view) {
  1293. self.labelIncomingOutgoing.text = "Busy".localized()
  1294. }
  1295. if self.buttonDecline.isDescendant(of: self.view) {
  1296. self.buttonDecline.removeFromSuperview()
  1297. }
  1298. if self.buttonAccept.isDescendant(of: self.view) {
  1299. self.buttonAccept.removeFromSuperview()
  1300. }
  1301. } else {
  1302. let indexPerson = self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[0]})
  1303. if indexPerson != nil {
  1304. if (self.dataPerson.count == 2) {
  1305. self.containerLabelName.forEach({ $0.subviews.forEach({ $0.removeFromSuperview() }) })
  1306. self.scrollRemoteView.subviews.forEach({ $0.removeFromSuperview() })
  1307. } else {
  1308. self.containerLabelName[indexPerson! + indexPerson!].subviews.forEach({ $0.removeFromSuperview() })
  1309. self.scrollRemoteView.subviews[indexPerson! + indexPerson!].removeFromSuperview()
  1310. self.containerLabelName[indexPerson! + indexPerson!].subviews.forEach({ $0.removeFromSuperview() })
  1311. self.scrollRemoteView.subviews[indexPerson! + indexPerson!].removeFromSuperview()
  1312. if indexPerson! + 1 <= self.listRemoteViewFix.count {
  1313. let viewAfterRemote = self.listRemoteViewFix[indexPerson! + 1]
  1314. let viewAfterName = self.containerLabelName[indexPerson! + 1]
  1315. viewAfterRemote.frame.origin.y = viewAfterRemote.frame.origin.y - 170
  1316. viewAfterName.frame.origin.y = viewAfterName.frame.origin.y - 170
  1317. UIView.animate(withDuration: 0.35, animations: {
  1318. self.scrollRemoteView.layoutIfNeeded()
  1319. })
  1320. }
  1321. }
  1322. }
  1323. if !onGoingCC.isEmpty {
  1324. if let pin = arrayMessage.first, let index = self.users.firstIndex(of: User(pin: String(pin))) {
  1325. self.users.remove(at: index)
  1326. if !onGoingCC.isEmpty && users.count != 0 {
  1327. DispatchQueue.main.async {
  1328. var members = ""
  1329. for user in self.users {
  1330. if members.isEmpty {
  1331. members = "\(user.pin)"
  1332. } else {
  1333. members = ",\(user.pin)"
  1334. }
  1335. }
  1336. UserDefaults.standard.set("\(members)", forKey: "membersCC")
  1337. }
  1338. }
  1339. }
  1340. }
  1341. self.dataPerson.remove(at: indexPerson!)
  1342. }
  1343. }
  1344. if (self.dataPerson.count == 1) {
  1345. DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
  1346. self.endAllCall()
  1347. if self.isInisiator && onGoingCC.isEmpty && !self.isPresent {
  1348. self.navigationController?.popViewController(animated: true)
  1349. } else {
  1350. self.dismiss(animated: true, completion: nil)
  1351. }
  1352. }
  1353. }
  1354. } else if (state == Nexilis.VIDEO_CALL_RINGING) {
  1355. DispatchQueue.main.async {
  1356. if (self.dataPerson.count > 1) {
  1357. if (self.dataPerson.count == 2) {
  1358. for i in 0...1{
  1359. self.scrollRemoteView.addSubview(self.listRemoteViewFix[i])
  1360. self.listRemoteViewFix[i].frame = CGRect(x: 0, y: 170 * i, width: 120, height: 160)
  1361. self.listRemoteViewFix[i].backgroundColor = .clear
  1362. self.listRemoteViewFix[i].makeRoundedView(radius: 8.0)
  1363. self.scrollRemoteView.addSubview(self.containerLabelName[i])
  1364. self.containerLabelName[i].frame = CGRect(x: 0, y: 170 * i, width: 120, height: 30)
  1365. self.containerLabelName[i].backgroundColor = .orangeBNI.withAlphaComponent(0.5)
  1366. self.containerLabelName[i].makeRoundedView(radius: 8.0)
  1367. let pictureImage = self.dataPerson[i]["picture"] ?? ""
  1368. let namePerson = self.dataPerson[i]["name"] ?? ""
  1369. if (!pictureImage!.isEmpty) {
  1370. self.listRemoteViewFix[i].setImage(name: pictureImage!)
  1371. self.listRemoteViewFix[i].contentMode = .scaleAspectFill
  1372. } else {
  1373. self.listRemoteViewFix[i].image = UIImage(systemName: "person")
  1374. self.listRemoteViewFix[i].backgroundColor = UIColor.systemGray6
  1375. self.listRemoteViewFix[i].contentMode = .scaleAspectFit
  1376. }
  1377. let labelName = UILabel()
  1378. self.containerLabelName[i].addSubview(labelName)
  1379. labelName.anchor(left: self.containerLabelName[i].leftAnchor, right: self.containerLabelName[i].rightAnchor, paddingLeft: 5, paddingRight: 5, centerX: self.containerLabelName[i].centerXAnchor, centerY: self.containerLabelName[i].centerYAnchor)
  1380. labelName.text = namePerson
  1381. labelName.textAlignment = .center
  1382. labelName.textColor = .white
  1383. }
  1384. self.scrollRemoteView.contentSize.height = CGFloat(170 * 2)
  1385. } else {
  1386. let i = self.dataPerson.count - 1
  1387. self.scrollRemoteView.addSubview(self.listRemoteViewFix[i])
  1388. self.listRemoteViewFix[i].frame = CGRect(x: 0, y: 170 * i, width: 120, height: 160)
  1389. self.listRemoteViewFix[i].backgroundColor = .clear
  1390. self.listRemoteViewFix[i].makeRoundedView(radius: 8.0)
  1391. self.scrollRemoteView.addSubview(self.containerLabelName[i])
  1392. self.containerLabelName[i].frame = CGRect(x: 0, y: 170 * i, width: 120, height: 30)
  1393. self.containerLabelName[i].backgroundColor = .orangeBNI.withAlphaComponent(0.5)
  1394. self.containerLabelName[i].makeRoundedView(radius: 8.0)
  1395. let pictureImage = self.dataPerson[self.dataPerson.count - 1]["picture"] ?? ""
  1396. let namePerson = self.dataPerson[self.dataPerson.count - 1]["name"] ?? ""
  1397. if (!pictureImage!.isEmpty) {
  1398. self.listRemoteViewFix[i].setImage(name: pictureImage!)
  1399. self.listRemoteViewFix[i].contentMode = .scaleAspectFill
  1400. } else {
  1401. self.listRemoteViewFix[i].image = UIImage(systemName: "person")
  1402. self.listRemoteViewFix[i].backgroundColor = UIColor.systemGray6
  1403. self.listRemoteViewFix[i].contentMode = .scaleAspectFit
  1404. }
  1405. self.scrollRemoteView.contentSize.height = CGFloat(170 * (i + 1))
  1406. let labelName = UILabel()
  1407. self.containerLabelName[i].addSubview(labelName)
  1408. labelName.anchor(left: self.containerLabelName[i].leftAnchor, right: self.containerLabelName[i].rightAnchor, paddingLeft: 5, paddingRight: 5, centerX: self.containerLabelName[i].centerXAnchor, centerY: self.containerLabelName[i].centerYAnchor)
  1409. labelName.text = namePerson
  1410. labelName.textAlignment = .center
  1411. labelName.textColor = .white
  1412. }
  1413. }
  1414. }
  1415. }
  1416. }
  1417. }
  1418. extension QmeraVideoViewController : WhiteboardReceiver {
  1419. func incomingWB(roomId: String) {
  1420. //print("incoming wb")
  1421. self.wbTimer.invalidate()
  1422. if(wbRoomId.isEmpty){
  1423. //print("wbroom empty")
  1424. DispatchQueue.main.async {
  1425. self.wbTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.runTimer), userInfo: nil, repeats: true)
  1426. }
  1427. let me = UserDefaults.standard.string(forKey: "me")!
  1428. var destString = ""
  1429. for d in dataPerson{
  1430. if d["f_pin"]!! == roomId.components(separatedBy: "wbvc")[0] {
  1431. continue
  1432. }
  1433. if destString.isEmpty{
  1434. destString = d["f_pin"]!!
  1435. } else {
  1436. destString = destString + ",\(d["f_pin"]!!)"
  1437. }
  1438. }
  1439. if destString.isEmpty {
  1440. UserDefaults.standard.set("\(roomId.components(separatedBy: "wbvc")[0]),\(me)", forKey: "wb_vc")
  1441. } else {
  1442. UserDefaults.standard.set("\(roomId.components(separatedBy: "wbvc")[0]),\(me),\(destString)", forKey: "wb_vc")
  1443. }
  1444. wbRoomId = roomId
  1445. }
  1446. }
  1447. func cancel(roomId: String) {
  1448. DispatchQueue.main.async {
  1449. self.wbTimer.invalidate()
  1450. self.wbBlink = false
  1451. self.buttonWB.backgroundColor = .lightGray
  1452. self.buttonWB.setNeedsDisplay()
  1453. }
  1454. wbRoomId = ""
  1455. }
  1456. @objc func runTimer(){
  1457. DispatchQueue.main.async {
  1458. self.wbBlink = !self.wbBlink
  1459. if(self.wbBlink){
  1460. //print("set wb blink on")
  1461. self.buttonWB.backgroundColor = .green
  1462. }
  1463. else {
  1464. //print("set wb blink off")
  1465. self.buttonWB.backgroundColor = .lightGray
  1466. }
  1467. self.buttonWB.setNeedsDisplay()
  1468. }
  1469. }
  1470. }