WebinarViewController.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. //
  2. // WebinarViewController.swift
  3. // Learn Genie
  4. //
  5. // Created by Suraj Kumar Mandal on 14/04/22.
  6. //
  7. import UIKit
  8. import JitsiMeetSDK
  9. import SideMenu
  10. class WebinarViewController: UIViewController {
  11. @IBOutlet var navigationBar: UINavigationBar!
  12. @IBOutlet var meetingTypeSegmentControl: UISegmentedControl!
  13. @IBOutlet var meetingTableView: UITableView!
  14. var joiningLinkTF: UITextField?
  15. let viewModel = WebinarViewModel()
  16. var refreshControl: UIRefreshControl!
  17. var meetingType = "Upcoming"
  18. fileprivate var jitsiMeetView: JitsiMeetView?
  19. var userId = Int()
  20. var meetingModel = [MeetingModel]()
  21. var groupModel = [GroupModel]()
  22. var upcomingArray = [MeetingModel]()
  23. var elapsedArray = [MeetingModel]()
  24. let userData = UserDefaults.standard.dictionary(forKey: Constant.userData)
  25. let userModelDB = DBManager.sharedInstance.database.objects(UserDetailsModel.self)
  26. var meetingTime = String()
  27. override func viewDidLoad() {
  28. super.viewDidLoad()
  29. // Do any additional setup after loading the view.
  30. viewModel.delegate = self
  31. meetingTableView.delegate = self
  32. meetingTableView.dataSource = self
  33. // Tableview pull to refresh
  34. refreshControl = UIRefreshControl()
  35. refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
  36. refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
  37. meetingTableView.addSubview(refreshControl)
  38. if let row = userModelDB.firstIndex(where: {$0.email == self.userData?["email"] as? String}) {
  39. userId = userModelDB[row].id
  40. }
  41. }
  42. override func viewWillAppear(_ animated: Bool) {
  43. navigationBar.topItem?.title = Helper.translateText(inputText: "Webinar")
  44. meetingTypeSegmentControl.setTitle(Helper.translateText(inputText: "Upcoming"), forSegmentAt: 0)
  45. meetingTypeSegmentControl.setTitle(Helper.translateText(inputText: "Elapsed"), forSegmentAt: 1)
  46. viewModel.meetingModel.removeAll()
  47. viewModel.groupModel.removeAll()
  48. viewModel.generateCookie()
  49. }
  50. func setupJitsi(isAdmin:Bool) {
  51. let defaultOptions = JitsiMeetConferenceOptions.fromBuilder { (builder) in
  52. // for JaaS replace url with https://8x8.vc
  53. builder.serverURL = URL(string: "https://meet.jit.si")
  54. let userInfo = JitsiMeetUserInfo()
  55. userInfo.displayName = (self.userData?["name"] as! String)
  56. //userInfo.email = self.userData?["email"] as! String
  57. builder.userInfo = userInfo
  58. // for JaaS use the obtained Jitsi JWT
  59. // builder.token = "SampleJWT"
  60. if isAdmin == true {
  61. // Set different feature flags
  62. builder.setFeatureFlag("add-people.enabled", withBoolean: true)
  63. builder.setFeatureFlag("invite.enabled", withBoolean: true)
  64. builder.setFeatureFlag("kick-out.enabled", withBoolean: true)
  65. builder.setFeatureFlag("live-streaming.enabled", withBoolean: true)
  66. builder.setFeatureFlag("server-url-change.enabled", withBoolean: true)
  67. builder.setFeatureFlag("video-share.enabled", withBoolean: true)
  68. builder.setFeatureFlag("ios.screensharing.enabled", withBoolean: true)
  69. builder.setFeatureFlag("recording.enabled", withBoolean: true)
  70. builder.setFeatureFlag("security-options.enabled", withBoolean: true)
  71. builder.setFeatureFlag("meeting-name.enabled", withBoolean: true)
  72. builder.setConfigOverride("disablePolls", withBoolean: false)
  73. builder.setConfigOverride("disableRemoteMute", withBoolean: false)
  74. } else {
  75. builder.setFeatureFlag("add-people.enabled", withBoolean: false)
  76. builder.setFeatureFlag("invite.enabled", withBoolean: false)
  77. builder.setFeatureFlag("kick-out.enabled", withBoolean: false)
  78. builder.setFeatureFlag("live-streaming.enabled", withBoolean: false)
  79. builder.setFeatureFlag("server-url-change.enabled", withBoolean: false)
  80. builder.setFeatureFlag("video-share.enabled", withBoolean: false)
  81. builder.setFeatureFlag("ios.screensharing.enabled", withBoolean: false)
  82. builder.setFeatureFlag("recording.enabled", withBoolean: false)
  83. builder.setFeatureFlag("security-options.enabled", withBoolean: false)
  84. builder.setFeatureFlag("meeting-name.enabled", withBoolean: true)
  85. builder.setConfigOverride("disablePolls", withBoolean: true)
  86. builder.setConfigOverride("disableRemoteMute", withBoolean: true)
  87. }
  88. // builder.setFeatureFlag("welcomepage.enabled", withValue: false)
  89. // builder.setFeatureFlag("video-share.enabled", withBoolean: false)
  90. // builder.setFeatureFlag("resolution", withBoolean: true)
  91. // builder.setFeatureFlag("ios.recording.enabled", withBoolean: true)
  92. // builder.setFeatureFlag("audio-mute.enabled", withBoolean: true)
  93. // builder.setFeatureFlag("chat.enabled", withBoolean: true)
  94. // builder.setFeatureFlag("video-mute.enabled", withBoolean: true)
  95. // builder.setFeatureFlag("android.audio-focus.disabled", withBoolean: false)
  96. // builder.setFeatureFlag("calendar.enabled", withBoolean: true)
  97. // builder.setFeatureFlag("call-integration.enabled", withBoolean: true)
  98. // builder.setFeatureFlag("close-captions.enabled", withBoolean: true)
  99. // builder.setFeatureFlag("conference-timer.enabled", withBoolean: true)
  100. // builder.setFeatureFlag("filmstrip.enabled", withBoolean: true)
  101. // builder.setFeatureFlag("notifications.enabled", withBoolean: false)
  102. // builder.setFeatureFlag("overflow-menu.enabled", withBoolean: false)
  103. // builder.setFeatureFlag("pip.enabled", withBoolean: false)
  104. // builder.setFeatureFlag("raise-hand.enabled", withBoolean: false)
  105. // builder.setFeatureFlag("tile-view.enabled", withBoolean: true)
  106. // builder.setFeatureFlag("toolbox.alwaysVisible", withBoolean: true)
  107. // builder.setFeatureFlag("toolbox.enabled", withBoolean: true)
  108. }
  109. JitsiMeet.sharedInstance().defaultConferenceOptions = defaultOptions
  110. }
  111. func configurationTextField(textField: UITextField!) {
  112. if (textField) != nil {
  113. self.joiningLinkTF = textField! //Save reference to the UITextField
  114. self.joiningLinkTF?.placeholder = "Type joining link here...";
  115. }
  116. }
  117. @objc func refresh(_ sender: Any) {
  118. // your code to reload tableView
  119. viewModel.meetingModel.removeAll()
  120. viewModel.groupModel.removeAll()
  121. viewModel.generateCookie()
  122. }
  123. func getCurrentDate() -> String {
  124. let date = Date()
  125. let df = DateFormatter()
  126. df.timeZone = TimeZone(identifier: "UTC")
  127. df.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
  128. let dateString = df.string(from: date)
  129. print(dateString)
  130. return dateString
  131. }
  132. func openJitsi(roomName:String, subject:String) {
  133. let room: String = roomName
  134. if(room.count < 1) {
  135. return
  136. }
  137. // create and configure jitsimeet view
  138. let jitsiMeetView = JitsiMeetView()
  139. jitsiMeetView.delegate = self
  140. self.jitsiMeetView = jitsiMeetView
  141. let options = JitsiMeetConferenceOptions.fromBuilder { (builder) in
  142. // for JaaS use <tenant>/<roomName> format
  143. builder.room = room
  144. builder.setSubject(subject)
  145. // Settings for audio and video
  146. // builder.audioMuted = true;
  147. // builder.videoMuted = true;
  148. }
  149. // setup view controller
  150. let vc = UIViewController()
  151. vc.modalPresentationStyle = .fullScreen
  152. vc.view = jitsiMeetView
  153. // join room and display jitsi-call
  154. jitsiMeetView.join(options)
  155. present(vc, animated: true, completion: nil)
  156. }
  157. fileprivate func cleanUp() {
  158. if(jitsiMeetView != nil) {
  159. dismiss(animated: true, completion: nil)
  160. jitsiMeetView = nil
  161. }
  162. }
  163. func getMeetingLinks() {
  164. self.upcomingArray.removeAll()
  165. self.elapsedArray.removeAll()
  166. for group in groupModel {
  167. let id = group.id
  168. for data in group.student {
  169. if data.studentId == userId {
  170. for meeting in meetingModel {
  171. let groupId = meeting.groupId
  172. if id == groupId {
  173. print(meeting.meetingSubject!)
  174. let interval = meeting.duration! * 60
  175. let date1 = meeting.meetingDateTime!.toDate()!.addingTimeInterval(TimeInterval(interval))
  176. let date2 = getCurrentDate().toDate()!
  177. if date1.isGreaterThanEqual(date2) {
  178. let id = meeting.id
  179. let userId = meeting.userId
  180. let groupId = meeting.groupId
  181. let duration = meeting.duration
  182. let meetingDateTime = meeting.meetingDateTime!
  183. let sessionID = meeting.sessionID
  184. let meetingSubject = meeting.meetingSubject
  185. let adminId = meeting.adminId
  186. let data = MeetingModel(id: id ?? 0, userId: userId ?? 0, groupId: groupId ?? 0, adminId: adminId ?? 0, duration: duration ?? 0, meetingDateTime: meetingDateTime , sessionID: sessionID ?? "", meetingSubject: meetingSubject ?? "")
  187. self.upcomingArray.append(data)
  188. } else {
  189. let id = meeting.id
  190. let userId = meeting.userId
  191. let groupId = meeting.groupId
  192. let duration = meeting.duration
  193. let meetingDateTime = meeting.meetingDateTime
  194. let sessionID = meeting.sessionID
  195. let meetingSubject = meeting.meetingSubject
  196. let adminId = meeting.adminId
  197. let data = MeetingModel(id: id ?? 0, userId: userId ?? 0, groupId: groupId ?? 0, adminId: adminId ?? 0, duration: duration ?? 0, meetingDateTime: meetingDateTime ?? "", sessionID: sessionID ?? "", meetingSubject: meetingSubject ?? "")
  198. self.elapsedArray.append(data)
  199. }
  200. }
  201. }
  202. }
  203. }
  204. }
  205. print("array data: \(upcomingArray.count), \(elapsedArray.count)")
  206. meetingTableView.reloadData()
  207. }
  208. func timeString(time: TimeInterval) -> String {
  209. //let hour = Int(time) / 3600
  210. let minute = Int(time) / 60 % 60
  211. let second = Int(time) % 60
  212. // return formated string
  213. return String(format: "%02i mins:%02i sec", minute, second)
  214. }
  215. /*
  216. // MARK: - Navigation
  217. // In a storyboard-based application, you will often want to do a little preparation before navigation
  218. override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  219. // Get the new view controller using segue.destination.
  220. // Pass the selected object to the new view controller.
  221. }
  222. */
  223. @IBAction func menuNavAction(_ sender: Any) {
  224. let menu = storyboard!.instantiateViewController(withIdentifier: "SideMenuNavigationController") as! SideMenuNavigationController
  225. present(menu, animated: true, completion: nil)
  226. }
  227. @IBAction func segmentedAction(_ sender: Any) {
  228. switch meetingTypeSegmentControl.selectedSegmentIndex
  229. {
  230. case 0:
  231. meetingType = "Upcoming"
  232. meetingTableView.reloadData()
  233. case 1:
  234. meetingType = "Elapsed"
  235. meetingTableView.reloadData()
  236. default:
  237. break
  238. }
  239. }
  240. }
  241. extension WebinarViewController: WebinarViewProtocol {
  242. func startLoader() {
  243. ActivityIndicator.start()
  244. }
  245. func stopLoader() {
  246. ActivityIndicator.stop()
  247. }
  248. func gotGroupList(groupModel: [GroupModel]) {
  249. self.groupModel.removeAll()
  250. self.groupModel = groupModel
  251. print("Group count: \(self.groupModel.count)")
  252. if Reachability.isConnectedToNetwork() {
  253. viewModel.getMeetingLists(offset: 0)
  254. } else {
  255. Alert.showInternetFailureAlert(on: self)
  256. }
  257. }
  258. func gotMeetingList(meetingModel: [MeetingModel]) {
  259. self.meetingModel.removeAll()
  260. self.meetingModel = meetingModel
  261. getMeetingLinks()
  262. refreshControl.endRefreshing()
  263. }
  264. }
  265. extension WebinarViewController: UITableViewDelegate, UITableViewDataSource {
  266. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  267. if meetingType == "Upcoming" {
  268. return upcomingArray.count
  269. } else {
  270. return elapsedArray.count
  271. }
  272. }
  273. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  274. guard let cell = tableView.dequeueReusableCell(withIdentifier: "WebinarTableViewCell", for: indexPath) as? WebinarTableViewCell else {
  275. return UITableViewCell()
  276. }
  277. if meetingType == "Upcoming" {
  278. let dateTime = upcomingArray[indexPath.row].meetingDateTime
  279. let dateFormatter = DateFormatter()
  280. dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
  281. dateFormatter.locale = Locale.current
  282. dateFormatter.timeZone = TimeZone.current
  283. let date = dateFormatter.date(from:dateTime!)
  284. dateFormatter.dateFormat = "dd/MM/yyyy"
  285. let finalDate = dateFormatter.string(from: date!)
  286. dateFormatter.dateFormat = "h:mm a"
  287. let finalTime = dateFormatter.string(from: date!)
  288. cell.layer.cornerRadius = 10
  289. cell.meetingNameLabel.text = upcomingArray[indexPath.row].meetingSubject
  290. cell.dateLabel.text = "Date: \(finalDate)"
  291. cell.timeLabel.text = "Time: \(finalTime)"
  292. meetingTime = finalTime
  293. } else {
  294. let dateTime = elapsedArray.reversed()[indexPath.row].meetingDateTime
  295. let dateFormatter = DateFormatter()
  296. dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
  297. dateFormatter.locale = Locale.current
  298. dateFormatter.timeZone = TimeZone.current
  299. let date = dateFormatter.date(from:dateTime!)
  300. dateFormatter.dateFormat = "dd/MM/yyyy"
  301. let finalDate = dateFormatter.string(from: date!)
  302. dateFormatter.dateFormat = "h:mm a"
  303. let finalTime = dateFormatter.string(from: date!)
  304. cell.layer.cornerRadius = 10
  305. cell.meetingNameLabel.text = elapsedArray.reversed()[indexPath.row].meetingSubject
  306. cell.dateLabel.text = "Date: \(finalDate)"
  307. cell.timeLabel.text = "Time: \(finalTime)"
  308. }
  309. return cell
  310. }
  311. func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  312. if meetingType == "Upcoming" {
  313. let interval = -10 * 60
  314. let date1 = upcomingArray[indexPath.row].meetingDateTime!.toDate()!.addingTimeInterval(TimeInterval(interval))
  315. let date2 = getCurrentDate().toDate()!
  316. if date1.isLessThanEqual(date2) {
  317. let room = "\(upcomingArray[indexPath.row].meetingSubject ?? "") - \(upcomingArray[indexPath.row].sessionID ?? "")"
  318. let meetingName = upcomingArray[indexPath.row].meetingSubject
  319. if Reachability.isConnectedToNetwork() {
  320. if userId == upcomingArray[indexPath.row].adminId {
  321. // Setup Jitsi
  322. setupJitsi(isAdmin: true)
  323. openJitsi(roomName: room, subject: meetingName ?? "")
  324. } else {
  325. // Setup Jitsi
  326. setupJitsi(isAdmin: false)
  327. openJitsi(roomName: room, subject: meetingName ?? "")
  328. }
  329. } else {
  330. Alert.showInternetFailureAlert(on: self)
  331. }
  332. } else {
  333. let waitTime = upcomingArray[indexPath.row].meetingDateTime?.toDate()?.timeIntervalSinceNow
  334. Alert.showAlert(on: self, with: "Meeting is at \(meetingTime)", message: "Meeting will start in \(timeString(time: TimeInterval(waitTime!))), Please join the meeting 10 min prior to meeting time.")
  335. }
  336. } else {
  337. self.view.makeToast("Meeting link expired!")
  338. tableView.deselectRow(at: indexPath, animated: true)
  339. }
  340. }
  341. }
  342. extension WebinarViewController: JitsiMeetViewDelegate {
  343. func ready(toClose data: [AnyHashable : Any]!) {
  344. cleanUp()
  345. }
  346. func participantJoined(_ data: [AnyHashable : Any]!) {
  347. print("Joined Participant: \(data)")
  348. }
  349. func participantLeft(_ data: [AnyHashable : Any]!) {
  350. print("Left Participant: \(data)")
  351. }
  352. }