QmeraVideoViewController.swift 73 KB

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