VideoViewController.swift 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. //
  2. // VideoViewController.swift
  3. // Qmera
  4. //
  5. // Created by Yayan Dwi on 07/09/21.
  6. //
  7. import UIKit
  8. import nuSDKService
  9. import AVFoundation
  10. class VideoViewController: UIViewController {
  11. @IBOutlet var zoomView: UIImageView!
  12. @IBOutlet var cameraView: UIImageView!
  13. @IBOutlet var buttonSwitchCamera: UIButton!
  14. @IBOutlet var buttonEndCall: UIButton!
  15. @IBOutlet var viewButtonDeclineAccept: UIView!
  16. @IBOutlet var buttonDeclineCall: UIButton!
  17. @IBOutlet var buttonAcceptCall: UIButton!
  18. @IBOutlet var buttonMuteVoice: UIButton!
  19. @IBOutlet var buttonSpeaker: UIButton!
  20. @IBOutlet var labelStatusCall: UILabel!
  21. @IBOutlet var imageProfile: UIImageView!
  22. @IBOutlet var listRemoteView: UITableView!
  23. var dataPerson: [[String: String?]] = []
  24. var isInisiator = true
  25. var isSpeaker = false
  26. var isMute = false
  27. var listRemoteViewFix: [UIImageView] = []
  28. override func viewWillDisappear(_ animated: Bool) {
  29. self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
  30. self.navigationController?.navigationBar.shadowImage = nil
  31. self.navigationController?.navigationBar.isTranslucent = false
  32. self.navigationController?.view.backgroundColor = nil
  33. self.navigationController?.navigationBar.titleTextAttributes = nil
  34. self.navigationController?.navigationBar.topItem?.backBarButtonItem = nil
  35. self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
  36. }
  37. func setStyleAppBar() {
  38. DispatchQueue.main.async {
  39. self.title = "Video Call"
  40. self.navigationController?.navigationBar.tintColor = UIColor.white
  41. self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
  42. self.navigationController?.navigationBar.shadowImage = UIImage()
  43. self.navigationController?.navigationBar.isTranslucent = true
  44. self.navigationController?.view.backgroundColor = .clear
  45. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  46. self.navigationController?.navigationBar.titleTextAttributes = textAttributes
  47. self.labelStatusCall.isHidden = true
  48. self.imageProfile.isHidden = true
  49. }
  50. }
  51. override func viewDidDisappear(_ animated: Bool) {
  52. NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil)
  53. NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "afterAddParticipantVideo"), object: nil)
  54. }
  55. override func viewDidLoad() {
  56. super.viewDidLoad()
  57. listRemoteView.delegate = self
  58. listRemoteView.dataSource = self
  59. title = dataPerson[0]["name"]!
  60. self.navigationController?.navigationBar.topItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
  61. imageProfile.circle()
  62. let pictureImage = dataPerson[0]["picture"]!
  63. if (pictureImage != "" && pictureImage != nil) {
  64. imageProfile.setImage(name: pictureImage!)
  65. imageProfile.contentMode = .scaleAspectFill
  66. }
  67. showButton(isShow: false)
  68. self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
  69. self.navigationItem.setHidesBackButton(true, animated: false)
  70. NotificationCenter.default.addObserver(self, selector: #selector(self.addCallParticipant(_:)), name: NSNotification.Name(rawValue: "afterAddParticipantVideo"), object: nil)
  71. NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil)
  72. if (dataPerson.count > 0) {
  73. if (isInisiator) {
  74. viewButtonDeclineAccept.isHidden = true
  75. buttonAcceptCall.isHidden = true
  76. buttonDeclineCall.isHidden = true
  77. buttonEndCall.circle()
  78. buttonEndCall.addTarget(self, action: #selector(didTapEndCallButton(sender:)), for: .touchUpInside)
  79. cameraView.makeRoundedView(radius: 8)
  80. API.initiateCCall(sParty: dataPerson[0]["f_pin"]!, nCamIdx: 1, nResIdx: 2, nVQuality: 2, ivRemoteView: listRemoteViewFix, ivLocalView: cameraView, ivRemoteZ: zoomView)
  81. } else {
  82. labelStatusCall.text = "Incoming Video Call"
  83. buttonEndCall.isHidden = true
  84. self.viewButtonDeclineAccept.clipsToBounds = true
  85. viewButtonDeclineAccept.layer.cornerRadius = 15
  86. viewButtonDeclineAccept.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
  87. buttonDeclineCall.layer.cornerRadius = 5.0
  88. buttonAcceptCall.layer.cornerRadius = 5.0
  89. buttonDeclineCall.addTarget(self, action: #selector(didTapDeclineCallButton(sender:)), for: .touchUpInside)
  90. buttonAcceptCall.addTarget(self, action: #selector(didTapAcceptCallButton(sender:)), for: .touchUpInside)
  91. }
  92. }
  93. }
  94. @objc func didTapAddParticipantButton(sender: AnyObject){
  95. if let contactViewController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID") as? ContactCallViewController {
  96. contactViewController.isAddParticipantVideo = true
  97. contactViewController.connectedCall = dataPerson
  98. show(contactViewController, sender: nil)
  99. }
  100. }
  101. @objc func didTapEndCallButton(sender: AnyObject){
  102. setSpeaker(isSpeaker: false)
  103. showButton(isShow: false)
  104. endAllCall()
  105. if isInisiator {
  106. self.navigationController?.popViewController(animated: true)
  107. } else {
  108. self.dismiss(animated: true, completion: nil)
  109. }
  110. }
  111. @objc func didTapSpeakerButton(sender: AnyObject){
  112. setSpeaker(isSpeaker: !(self.isSpeaker))
  113. }
  114. @objc func didTapSwitchCameraButton(sender: AnyObject){
  115. API.changeCameraParam(nCameraIdx: 1, nResolutionIndex: 1, nQuality: 1)
  116. }
  117. @objc func didTapDeclineCallButton(sender: AnyObject){
  118. showButton(isShow: false)
  119. endAllCall()
  120. if isInisiator {
  121. self.navigationController?.popViewController(animated: true)
  122. } else {
  123. self.dismiss(animated: true, completion: nil)
  124. }
  125. }
  126. @objc func didTapAcceptCallButton(sender: AnyObject){
  127. cameraView.makeRoundedView(radius: 8)
  128. API.receiveCCall(sParty: dataPerson[0]["f_pin"]!, nCamIdx: 1, nResIdx: 2, nVQuality: 2, ivRemoteView: listRemoteViewFix, ivLocalView: cameraView,ivRemoteZ: zoomView)
  129. }
  130. @objc func onStatusCall(_ notification: NSNotification) {
  131. let data = notification.userInfo
  132. let state = (data?["state"] ?? 0) as! Int
  133. let message = (data?["message"] ?? "") as! String
  134. var remoteChannel = [String:String]()
  135. let arrayMessage = message.split(separator: ",")
  136. // let me = UserDefaults.standard.string(forKey: "me")!
  137. if(state == DigiX.VIDEO_CALL_ZOOM){
  138. DispatchQueue.main.async {
  139. self.zoomView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi * 3)/2)
  140. }
  141. }
  142. else if (state == DigiX.VIDEO_CAMERA_PARAMS_CHANED){
  143. let channel = arrayMessage[arrayMessage.count - 1]
  144. if(remoteChannel[String(channel)] != "2"){
  145. DispatchQueue.main.async {
  146. if(arrayMessage[arrayMessage.count - 2] == "0"){ // back camera
  147. self.zoomView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi)/2)
  148. }
  149. else { // front camera
  150. self.zoomView.transform = CGAffineTransform.init(scaleX: -2, y: 2).rotated(by: (CGFloat.pi * 3)/2)
  151. }
  152. }
  153. }
  154. }
  155. else if (state == DigiX.VIDEO_CALL_OFFHOOK){
  156. let channel = arrayMessage[3]
  157. remoteChannel[String(channel)] = String(arrayMessage[5])
  158. if (arrayMessage[5] == "2") {
  159. DispatchQueue.main.async {
  160. self.zoomView.transform = CGAffineTransform.init(scaleX: -2, y: 2).rotated(by: (CGFloat.pi)/2)
  161. self.zoomView.contentMode = .scaleAspectFit
  162. if (self.dataPerson.count > 1) {
  163. if (self.dataPerson.count == 2) {
  164. self.listRemoteViewFix[0].transform = CGAffineTransform.init(scaleX: -2, y: 2).rotated(by: (CGFloat.pi * 5)/2)
  165. self.listRemoteViewFix[0].isHidden = false
  166. }
  167. let indexPerson = self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[1]})
  168. if (indexPerson != -1) {
  169. self.listRemoteViewFix[indexPerson!].transform = CGAffineTransform.init(scaleX: -2, y: 2).rotated(by: (CGFloat.pi * 5)/2)
  170. }
  171. }
  172. }
  173. }
  174. else {
  175. DispatchQueue.main.async {
  176. self.zoomView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi * 3)/2)
  177. self.zoomView.contentMode = .scaleAspectFit
  178. if (self.dataPerson.count > 1) {
  179. if (self.dataPerson.count == 2) {
  180. self.listRemoteViewFix[0].transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi)/2)
  181. }
  182. let indexPerson = self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[1]})
  183. if (indexPerson != -1) {
  184. self.listRemoteViewFix[indexPerson!].transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi)/2)
  185. }
  186. }
  187. }
  188. }
  189. if (!self.isSpeaker) {
  190. setSpeaker(isSpeaker: true)
  191. }
  192. showButton(isShow: true)
  193. setStyleAppBar()
  194. } else if (state == DigiX.VIDEO_CALL_END || state == DigiX.AUDIO_CALL_END) {
  195. DispatchQueue.main.async {
  196. if (self.dataPerson.count == 1) {
  197. // let channel = arrayMessage[1]
  198. // if(Int(arrayMessage[2])! == 2 && !self.listRemoteViewFix.isEmpty) {
  199. // self.listRemoteViewFix[0].isHidden = true
  200. // self.listRemoteViewFix[1].isHidden = true
  201. // } else if(!self.listRemoteViewFix.isEmpty){
  202. // self.listRemoteViewFix[Int(channel)!].isHidden = true
  203. // }
  204. if (self.labelStatusCall.superview == nil) {
  205. self.labelStatusCall.isHidden = false
  206. self.labelStatusCall.textColor = UIColor.white
  207. }
  208. self.labelStatusCall.text = "Video call is over"
  209. self.buttonEndCall.isHidden = true
  210. self.setSpeaker(isSpeaker: false)
  211. self.showButton(isShow: false)
  212. if (!self.isInisiator && !self.isSpeaker) {
  213. self.viewButtonDeclineAccept.isHidden = true
  214. }
  215. } else {
  216. let indexPerson = self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[0]})
  217. if (self.dataPerson.count == 2) {
  218. let cell0 = self.listRemoteView.cellForRow(at: IndexPath(row: 0, section: 0)) as! CustomCellRemoteView
  219. let cell1 = self.listRemoteView.cellForRow(at: IndexPath(row: 0, section: 1)) as! CustomCellRemoteView
  220. cell0.isHidden = true
  221. cell1.isHidden = true
  222. } else {
  223. let indexPath = IndexPath(row: 0, section: indexPerson!)
  224. let cell = self.listRemoteView.cellForRow(at: indexPath) as! CustomCellRemoteView
  225. cell.isHidden = true
  226. }
  227. self.dataPerson.remove(at: indexPerson!)
  228. }
  229. }
  230. if (self.dataPerson.count == 1) {
  231. DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
  232. self.endAllCall()
  233. if self.isInisiator {
  234. self.navigationController?.popViewController(animated: true)
  235. } else {
  236. self.dismiss(animated: true, completion: nil)
  237. }
  238. }
  239. }
  240. } else if (state == DigiX.OFFLINE) {
  241. DispatchQueue.main.async {
  242. self.buttonEndCall.isHidden = true
  243. self.labelStatusCall.text = "Offline"
  244. }
  245. DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
  246. self.endAllCall()
  247. if self.isInisiator {
  248. self.navigationController?.popViewController(animated: true)
  249. } else {
  250. self.dismiss(animated: true, completion: nil)
  251. }
  252. }
  253. } else if (state == DigiX.BUSY) {
  254. DispatchQueue.main.async {
  255. if (self.dataPerson.count == 1) {
  256. self.buttonEndCall.isHidden = true
  257. self.labelStatusCall.text = "Busy"
  258. } else {
  259. let indexPerson = self.dataPerson.firstIndex(where: {$0["f_pin"]!! == arrayMessage[0]})
  260. if (self.dataPerson.count == 2) {
  261. let cell0 = self.listRemoteView.cellForRow(at: IndexPath(row: 0, section: 0)) as! CustomCellRemoteView
  262. let cell1 = self.listRemoteView.cellForRow(at: IndexPath(row: 0, section: 1)) as! CustomCellRemoteView
  263. cell0.isHidden = true
  264. cell1.isHidden = true
  265. } else {
  266. let indexPath = IndexPath(row: 0, section: indexPerson!)
  267. let cell = self.listRemoteView.cellForRow(at: indexPath) as! CustomCellRemoteView
  268. cell.isHidden = true
  269. }
  270. self.dataPerson.remove(at: indexPerson!)
  271. }
  272. }
  273. if (self.dataPerson.count == 1) {
  274. DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
  275. self.endAllCall()
  276. if self.isInisiator {
  277. self.navigationController?.popViewController(animated: true)
  278. } else {
  279. self.dismiss(animated: true, completion: nil)
  280. }
  281. }
  282. }
  283. } else if (state == DigiX.VIDEO_CALL_RINGING) {
  284. DispatchQueue.main.async {
  285. if (self.dataPerson.count > 1) {
  286. if (self.dataPerson.count == 2) {
  287. let indexPath = IndexPath(row: 0, section: 0)
  288. let cell = self.listRemoteView.cellForRow(at: indexPath) as! CustomCellRemoteView
  289. cell.containerViewImage.isHidden = false
  290. }
  291. let indexPath = IndexPath(row: 0, section: self.dataPerson.count - 1)
  292. let cell = self.listRemoteView.cellForRow(at: indexPath) as! CustomCellRemoteView
  293. cell.containerViewImage.isHidden = false
  294. let pictureImage = self.dataPerson[self.dataPerson.count - 1]["picture"]!
  295. if (pictureImage != "" && pictureImage != nil) {
  296. cell.remoteView.setImage(name: pictureImage!)
  297. cell.remoteView.contentMode = .scaleAspectFill
  298. } else {
  299. cell.remoteView.image = UIImage(systemName: "person")
  300. cell.remoteView.backgroundColor = UIColor.systemGray6
  301. cell.remoteView.contentMode = .scaleAspectFill
  302. }
  303. cell.labelRemoteView.text = self.dataPerson[self.dataPerson.count - 1]["name"]!
  304. }
  305. }
  306. }
  307. }
  308. func setSpeaker(isSpeaker: Bool) {
  309. // DispatchQueue.main.async {
  310. // if (isSpeaker) {
  311. // self.buttonSpeaker.backgroundColor = UIColor.systemGray4
  312. //
  313. // } else {
  314. // self.buttonSpeaker.backgroundColor = UIColor.systemBlue
  315. // }
  316. // self.isSpeaker = isSpeaker
  317. // }
  318. // let session = AVAudioSession.sharedInstance()
  319. // var _: Error?
  320. // if isSpeaker {
  321. // try? session.setCategory(AVAudioSession.Category.playAndRecord)
  322. // try? session.setMode(AVAudioSession.Mode.voiceChat)
  323. // try? session.overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
  324. // } else {
  325. // try? session.setCategory(.ambient)
  326. // try? session.setMode(.default)
  327. // try? session.overrideOutputAudioPort(.none)
  328. // }
  329. // try? session.setActive(true)
  330. }
  331. func setMicrophone(isMute: Bool) {
  332. if (isMute) {
  333. DispatchQueue.main.async {
  334. self.buttonSpeaker.backgroundColor = UIColor.systemBlue
  335. }
  336. } else {
  337. DispatchQueue.main.async {
  338. self.buttonMuteVoice.backgroundColor = UIColor.systemGray4
  339. }
  340. }
  341. }
  342. func showButton(isShow: Bool) {
  343. if (isShow) {
  344. DispatchQueue.main.async {
  345. self.buttonSwitchCamera.isHidden = false
  346. self.buttonMuteVoice.isHidden = false
  347. self.buttonSpeaker.isHidden = false
  348. self.buttonSwitchCamera.circle()
  349. self.buttonMuteVoice.circle()
  350. self.buttonSpeaker.circle()
  351. self.buttonSpeaker.addTarget(self, action: #selector(self.didTapSpeakerButton(sender:)), for: .touchUpInside)
  352. self.buttonSwitchCamera.addTarget(self, action: #selector(self.didTapSwitchCameraButton(sender:)), for: .touchUpInside)
  353. let addParticipantImage = UIImage(systemName: "person.crop.circle.badge.plus")?.flipHorizontally()
  354. let buttonAddParticipant = UIBarButtonItem(image: addParticipantImage, style: .plain, target: self, action: #selector(self.didTapAddParticipantButton(sender:)))
  355. self.navigationItem.rightBarButtonItem = buttonAddParticipant
  356. if (!self.isInisiator) {
  357. self.viewButtonDeclineAccept.isHidden = true
  358. self.buttonEndCall.isHidden = false
  359. self.buttonEndCall.circle()
  360. self.buttonEndCall.addTarget(self, action: #selector(self.didTapEndCallButton(sender:)), for: .touchUpInside)
  361. }
  362. }
  363. } else {
  364. DispatchQueue.main.async {
  365. self.buttonSwitchCamera.isHidden = true
  366. self.buttonMuteVoice.isHidden = true
  367. self.buttonSpeaker.isHidden = true
  368. }
  369. }
  370. }
  371. func endAllCall() {
  372. API.terminateCall(sParty: nil)
  373. cameraView = nil
  374. zoomView = nil
  375. listRemoteViewFix.removeAll()
  376. }
  377. @objc func addCallParticipant(_ notification: NSNotification) {
  378. let data = notification.userInfo
  379. DispatchQueue.main.async {
  380. var row: [String: String?] = [:]
  381. row["f_pin"] = data?["f_pin"] as? String
  382. row["name"] = data?["name"] as? String
  383. row["picture"] = data?["picture"] as? String
  384. row["isOfficial"] = data?["isOfficial"] as? String
  385. row["deviceId"] = data?["deviceId"] as? String
  386. row["isOffline"] = data?["isOffline"] as? String
  387. row["user_type"] = data?["user_type"] as? String
  388. self.dataPerson.append(row)
  389. }
  390. cameraView.makeRoundedView(radius: 8)
  391. API.initiateCCall(sParty: data?["f_pin"] as? String, nCamIdx: 1, nResIdx: 2, nVQuality: 2, ivRemoteView: listRemoteViewFix, ivLocalView: cameraView,ivRemoteZ: zoomView)
  392. }
  393. }
  394. extension UIImage {
  395. func flipHorizontally() -> UIImage? {
  396. UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
  397. let context = UIGraphicsGetCurrentContext()!
  398. context.translateBy(x: self.size.width/2, y: self.size.height/2)
  399. context.scaleBy(x: -1.0, y: 1.0)
  400. context.translateBy(x: -self.size.width/2, y: -self.size.height/2)
  401. self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
  402. let newImage = UIGraphicsGetImageFromCurrentImageContext()
  403. UIGraphicsEndImageContext()
  404. return newImage
  405. }
  406. }
  407. extension VideoViewController: UITableViewDelegate, UITableViewDataSource {
  408. func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  409. }
  410. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  411. return 1
  412. }
  413. func numberOfSections(in tableView: UITableView) -> Int {
  414. return 5
  415. }
  416. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  417. let cell = tableView.dequeueReusableCell(withIdentifier: "remoteViewCell", for: indexPath ) as! CustomCellRemoteView
  418. if (listRemoteViewFix.count < 5) {
  419. cell.containerViewImage.makeRoundedView(radius: 8)
  420. cell.remoteView.makeRoundedView(radius: 8)
  421. cell.containerLabel.makeRoundedView(radius: 5)
  422. if(indexPath.section == 0) {
  423. cell.labelRemoteView.text = self.dataPerson[indexPath.section]["name"] ?? ""
  424. let pictureImage = self.dataPerson[indexPath.section]["picture"]!
  425. if (pictureImage != "" && pictureImage != nil) {
  426. cell.remoteView.setImage(name: pictureImage!)
  427. cell.remoteView.contentMode = .scaleAspectFill
  428. } else {
  429. cell.remoteView.image = UIImage(systemName: "person")
  430. cell.remoteView.backgroundColor = UIColor.systemGray6
  431. cell.remoteView.contentMode = .scaleAspectFill
  432. }
  433. }
  434. cell.containerViewImage.isHidden = true
  435. listRemoteViewFix.append(cell.remoteView)
  436. }
  437. return cell
  438. }
  439. func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  440. return 160
  441. }
  442. func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
  443. return 20
  444. }
  445. func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
  446. let headerView = UIView()
  447. headerView.backgroundColor = UIColor.clear
  448. return headerView
  449. }
  450. }
  451. extension UIViewController{
  452. func showToast(message : String, seconds: Double){
  453. let alert = LibAlertController(title: nil, message: message, preferredStyle: .alert)
  454. alert.view.backgroundColor = .black
  455. alert.view.alpha = 0.5
  456. alert.view.layer.cornerRadius = 15
  457. self.present(alert, animated: true)
  458. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) {
  459. alert.dismiss(animated: true)
  460. }
  461. }
  462. }
  463. extension UIView {
  464. func makeRoundedView(radius: CGFloat) {
  465. self.layer.cornerRadius = radius
  466. self.clipsToBounds = true
  467. self.layer.masksToBounds = true
  468. }
  469. }
  470. class CustomCellRemoteView: UITableViewCell {
  471. @IBOutlet var remoteView: UIImageView!
  472. @IBOutlet var containerViewImage: UIView!
  473. @IBOutlet var labelRemoteView: UILabel!
  474. @IBOutlet var containerLabel: UIView!
  475. }