ContactChatViewController.swift 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328
  1. //
  2. // ContactChatViewController.swift
  3. // Qmera
  4. //
  5. // Created by Yayan Dwi on 22/09/21.
  6. //
  7. import UIKit
  8. import FMDB
  9. import NotificationBannerSwift
  10. import Toast_Swift
  11. class ContactChatViewController: UITableViewController {
  12. deinit {
  13. //print(#function, ">>>> TADAA")
  14. NotificationCenter.default.removeObserver(self)
  15. }
  16. var isChooser: ((String, String) -> ())?
  17. var isAdmin: Bool = false
  18. var chats: [Chat] = []
  19. var contacts: [User] = []
  20. var groups: [Group] = []
  21. var groupMap: [String:Int] = [:]
  22. var searchController: UISearchController!
  23. var segment: UISegmentedControl!
  24. var fillteredData: [Any] = []
  25. var isSearchBarEmpty: Bool {
  26. return searchController.searchBar.text!.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
  27. }
  28. var isFilltering: Bool {
  29. return !isSearchBarEmpty
  30. }
  31. var noData = false
  32. var noUCList = false
  33. func filterContentForSearchText(_ searchText: String) {
  34. func filterContact() {
  35. Utils.inTabChats = false
  36. fillteredData = self.contacts.filter { $0.fullName.lowercased().contains(searchText.lowercased()) }
  37. }
  38. func filterGroup() {
  39. Utils.inTabChats = false
  40. fillteredData = self.groups.filter { $0.name.lowercased().contains(searchText.lowercased()) }
  41. }
  42. if !searchText.isEmpty {
  43. if segment.numberOfSegments == 3 {
  44. switch segment.selectedSegmentIndex {
  45. case 1:
  46. Utils.inTabChats = false
  47. fillteredData = self.contacts.filter { $0.fullName.lowercased().contains(searchText.lowercased()) }
  48. case 2:
  49. Utils.inTabChats = false
  50. fillteredData = self.groups.filter { $0.name.lowercased().contains(searchText.lowercased()) }
  51. default:
  52. Utils.inTabChats = true
  53. fillteredData = self.chats.filter { $0.name.lowercased().contains(searchText.lowercased()) || $0.messageText.lowercased().contains(searchText.lowercased()) }
  54. }
  55. } else {
  56. switch segment.selectedSegmentIndex {
  57. case 1:
  58. filterGroup()
  59. default:
  60. filterContact()
  61. }
  62. }
  63. }
  64. tableView.reloadData()
  65. }
  66. override func viewDidLoad() {
  67. super.viewDidLoad()
  68. let me = UserDefaults.standard.string(forKey: "me")!
  69. Database.shared.database?.inTransaction({ fmdb, rollback in
  70. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select FIRST_NAME, LAST_NAME, IMAGE_ID, USER_TYPE from BUDDY where F_PIN = '\(me)'"), cursor.next() {
  71. isAdmin = cursor.string(forColumnIndex: 3) == "23" || cursor.string(forColumnIndex: 3) == "24"
  72. cursor.close()
  73. }
  74. })
  75. // navigationController?.navigationBar.prefersLargeTitles = true
  76. navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel".localized(), style: .plain, target: self, action: #selector(cancel(sender:)))
  77. let childrenMenu : [UIAction] = [
  78. UIAction(title: "Create Group".localized(), image: UIImage(systemName: "person.and.person"), handler: {[weak self](_) in
  79. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "createGroupNav") as! UINavigationController
  80. let vc = controller.topViewController as! GroupCreateViewController
  81. vc.isDismiss = { id in
  82. self?.groupMap.removeAll()
  83. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "groupDetailView") as! GroupDetailViewController
  84. controller.data = id
  85. self?.navigationController?.show(controller, sender: nil)
  86. }
  87. self?.navigationController?.present(controller, animated: true, completion: nil)
  88. }),
  89. UIAction(title: "Add Friends".localized(), image: UIImage(systemName: "person.badge.plus"), handler: {[weak self](_) in
  90. self?.addFriend(sender: UIBarButtonItem())
  91. }),
  92. // UIAction(title: "Configure Email", image: UIImage(systemName: "mail"), handler: {[weak self](_) in
  93. //
  94. // }),
  95. UIAction(title: "Favorite Messages".localized(), image: UIImage(systemName: "star"), handler: {[weak self](_) in
  96. let editorStaredVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "staredVC") as! EditorStarMessages
  97. self?.navigationController?.show(editorStaredVC, sender: nil)
  98. }),
  99. ]
  100. //debug only
  101. // isAdmin = true
  102. // if(isAdmin){
  103. // childrenMenu.append(UIAction(title: "Broadcast Message".localized(), image: UIImage(systemName: "envelope.open"), handler: {[weak self](_) in
  104. // let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "broadcastNav")
  105. // controller.modalPresentationStyle = .fullScreen
  106. // self?.navigationController?.present(controller, animated: true, completion: nil)
  107. // }))
  108. // childrenMenu.append(UIAction(title: "Live Streaming".localized(), image: UIImage(systemName: "video.bubble.left"), handler: {[weak self](_) in
  109. // let navigationController = UINavigationController(rootViewController: QmeraCreateStreamingViewController())
  110. // navigationController.modalPresentationStyle = .fullScreen
  111. // navigationController.navigationBar.tintColor = .white
  112. // navigationController.navigationBar.barTintColor = .mainColor
  113. // navigationController.navigationBar.isTranslucent = false
  114. // navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  115. // navigationController.navigationBar.barStyle = .black
  116. // let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white]
  117. // UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  118. // let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  119. // navigationController.navigationBar.titleTextAttributes = textAttributes
  120. // navigationController.view.backgroundColor = .mainColor
  121. // self?.navigationController?.present(navigationController, animated: true, completion: nil)
  122. // }))
  123. // }
  124. if noUCList {
  125. let buttonAddFriend = UIBarButtonItem(image: UIImage(systemName: "person.badge.plus", withConfiguration: UIImage.SymbolConfiguration(pointSize: 18, weight: .regular, scale: .default))?.withTintColor(.white), style: .plain, target: self, action: #selector(addFriend(sender:)))
  126. navigationItem.rightBarButtonItem = buttonAddFriend
  127. } else {
  128. let menu = UIMenu(title: "", children: childrenMenu)
  129. navigationItem.rightBarButtonItem = UIBarButtonItem(title: nil, image: UIImage(systemName: "ellipsis"), primaryAction: .none, menu: menu)
  130. }
  131. searchController = UISearchController(searchResultsController: nil)
  132. searchController.delegate = self
  133. searchController.searchResultsUpdater = self
  134. searchController.searchBar.autocapitalizationType = .none
  135. searchController.searchBar.delegate = self
  136. searchController.searchBar.barTintColor = .secondaryColor
  137. searchController.searchBar.searchTextField.backgroundColor = .secondaryColor
  138. searchController.obscuresBackgroundDuringPresentation = false
  139. searchController.searchBar.setMagnifyingGlassColorTo(color: .mainColor)
  140. searchController.searchBar.tintColor = .mainColor
  141. searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Search".localized(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)])
  142. navigationItem.searchController = searchController
  143. navigationItem.hidesSearchBarWhenScrolling = false
  144. definesPresentationContext = true
  145. var dataSegment = ["Chats".localized(), "Contacts".localized(), "Groups".localized()]
  146. if noUCList{
  147. dataSegment = ["Contacts".localized(), "Groups".localized()]
  148. }
  149. segment = UISegmentedControl(items: dataSegment)
  150. segment.sizeToFit()
  151. segment.selectedSegmentIndex = 0
  152. segment.addTarget(self, action: #selector(segmentChanged(sender:)), for: .valueChanged)
  153. segment.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 12.0)], for: .normal)
  154. Utils.inTabChats = true
  155. NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusChat), object: nil)
  156. NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
  157. NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onMember"), object: nil)
  158. NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil)
  159. tableView.tableHeaderView = segment
  160. tableView.tableFooterView = UIView()
  161. pullBuddy()
  162. }
  163. override func viewWillAppear(_ animated: Bool) {
  164. let attributes = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16.0), NSAttributedString.Key.foregroundColor: UIColor.white]
  165. let navBarAppearance = UINavigationBarAppearance()
  166. navBarAppearance.configureWithOpaqueBackground()
  167. navBarAppearance.backgroundColor = UIColor.mainColor
  168. navBarAppearance.titleTextAttributes = attributes
  169. navigationController?.navigationBar.standardAppearance = navBarAppearance
  170. navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
  171. // removeAllData()
  172. getData()
  173. }
  174. override func viewWillDisappear(_ animated: Bool) {
  175. Utils.inTabChats = false
  176. }
  177. override func viewDidAppear(_ animated: Bool) {
  178. if isChooser != nil {
  179. self.navigationController?.navigationBar.topItem?.title = "Forward Messages".localized()
  180. self.navigationController?.navigationBar.setNeedsLayout()
  181. } else if noUCList{
  182. self.navigationController?.navigationBar.topItem?.title = "Start Chat".localized()
  183. self.navigationController?.navigationBar.setNeedsLayout()
  184. } else {
  185. self.navigationController?.navigationBar.topItem?.title = "Start Conversation".localized()
  186. self.navigationController?.navigationBar.setNeedsLayout()
  187. }
  188. DispatchQueue.global().async {
  189. self.getOpenGroups(listGroups: self.groups, completion: { g in
  190. DispatchQueue.main.async {
  191. for og in g {
  192. if self.groups.first(where: { $0.id == og.id }) == nil {
  193. self.groups.append(og)
  194. }
  195. }
  196. DispatchQueue.main.async {
  197. self.tableView.reloadData()
  198. }
  199. }
  200. })
  201. }
  202. if segment.selectedSegmentIndex == 0 {
  203. Utils.inTabChats = true
  204. }
  205. }
  206. @objc func addFriend(sender: UIBarButtonItem) {
  207. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "addFriendNav") as! UINavigationController
  208. if let vc = controller.viewControllers.first as? AddFriendTableViewController {
  209. vc.isDismiss = {
  210. self.getContacts {
  211. DispatchQueue.main.async {
  212. self.tableView.reloadData()
  213. }
  214. }
  215. }
  216. }
  217. navigationController?.present(controller, animated: true, completion: nil)
  218. }
  219. // func removeAllData() {
  220. // groups.removeAll()
  221. // groupMap.removeAll()
  222. // chats.removeAll()
  223. // tableView.reloadData()
  224. // }
  225. @objc func onReload(notification: NSNotification) {
  226. let data:[AnyHashable : Any] = notification.userInfo!
  227. if data["member"] as? String == UserDefaults.standard.string(forKey: "me") {
  228. DispatchQueue.main.async {
  229. self.getData()
  230. }
  231. } else if data["state"] as? Int == 99 {
  232. //print(("MASUK 99")
  233. DispatchQueue.main.async {
  234. self.getData()
  235. }
  236. }
  237. }
  238. @objc func onReceiveMessage(notification: NSNotification) {
  239. DispatchQueue.main.async { [self] in
  240. let data:[AnyHashable : Any] = notification.userInfo!
  241. if let dataMessage = data["message"] as? TMessage {
  242. let chatData = dataMessage.mBodies
  243. if chatData[CoreMessage_TMessageKey.IS_CALL_CENTER] == nil || chatData[CoreMessage_TMessageKey.IS_CALL_CENTER] == "0" {
  244. var indexChat: Int?
  245. if chatData[CoreMessage_TMessageKey.MESSAGE_SCOPE_ID] == "3" && chatData[CoreMessage_TMessageKey.F_PIN] != User.getMyPin() {
  246. indexChat = chats.firstIndex(where: { $0.fpin == chatData[CoreMessage_TMessageKey.F_PIN] })
  247. } else if chatData[CoreMessage_TMessageKey.MESSAGE_SCOPE_ID] == "4" && chatData[CoreMessage_TMessageKey.F_PIN] != User.getMyPin() {
  248. indexChat = chats.firstIndex(where: { (chatData[CoreMessage_TMessageKey.CHAT_ID] ?? "").isEmpty ? $0.pin == chatData[CoreMessage_TMessageKey.L_PIN] : $0.pin == chatData[CoreMessage_TMessageKey.CHAT_ID] })
  249. }
  250. let newChat = Chat.getData(messageId: chatData[CoreMessage_TMessageKey.MESSAGE_ID] ?? "")
  251. if newChat.count > 0 {
  252. if indexChat != nil {
  253. chats[0] = newChat[0]
  254. let indexPathToMove = IndexPath(row: indexChat!, section: 0)
  255. let indexPathNewPosition = IndexPath(row: 0, section: 0)
  256. tableView.performBatchUpdates({
  257. tableView.moveRow(at: indexPathToMove, to: indexPathNewPosition)
  258. }, completion: nil)
  259. tableView.beginUpdates()
  260. tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none)
  261. tableView.endUpdates()
  262. } else {
  263. if noData {
  264. chats.insert(newChat[0], at: 0)
  265. tableView.reloadData()
  266. } else {
  267. chats.insert(newChat[0], at: 0)
  268. tableView.beginUpdates()
  269. tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .none)
  270. tableView.endUpdates()
  271. }
  272. }
  273. }
  274. }
  275. }
  276. }
  277. }
  278. @objc func onStatusChat(notification: NSNotification) {
  279. DispatchQueue.main.async { [self] in
  280. let data:[AnyHashable : Any] = notification.userInfo!
  281. if let dataMessage = data["message"] as? TMessage {
  282. let indexChat = chats.firstIndex(where: { (dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)).contains(",") ? $0.messageId == (dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)).components(separatedBy: ",")[1] : $0.messageId == dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID) })
  283. if indexChat != nil {
  284. tableView.beginUpdates()
  285. tableView.reloadRows(at: [IndexPath(row: indexChat!, section: 0)], with: .none)
  286. tableView.endUpdates()
  287. }
  288. }
  289. }
  290. }
  291. @objc func add(sender: Any) {
  292. }
  293. @objc func cancel(sender: Any) {
  294. navigationController?.dismiss(animated: true, completion: nil)
  295. }
  296. @objc func segmentChanged(sender: Any) {
  297. filterContentForSearchText(searchController.searchBar.text!)
  298. }
  299. // MARK: - Data source
  300. func getData() {
  301. getChats {
  302. self.getContacts {
  303. self.getGroups { g1 in
  304. self.groupMap.removeAll()
  305. self.groups = g1
  306. DispatchQueue.main.async {
  307. self.tableView.reloadData()
  308. }
  309. }
  310. }
  311. }
  312. }
  313. func getChats(completion: @escaping ()->()) {
  314. DispatchQueue.global().async {
  315. self.chats = Chat.getData()
  316. completion()
  317. }
  318. }
  319. private func getContacts(completion: @escaping ()->()) {
  320. self.contacts.removeAll()
  321. DispatchQueue.global().async {
  322. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  323. if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT f_pin, first_name, last_name, image_id, official_account, user_type FROM BUDDY where f_pin <> '\(UserDefaults.standard.string(forKey: "me")!)' order by 5 desc, 2 collate nocase asc") {
  324. while cursorData.next() {
  325. let user = User(pin: cursorData.string(forColumnIndex: 0) ?? "",
  326. firstName: cursorData.string(forColumnIndex: 1) ?? "",
  327. lastName: cursorData.string(forColumnIndex: 2) ?? "",
  328. thumb: cursorData.string(forColumnIndex: 3) ?? "",
  329. userType: cursorData.string(forColumnIndex: 5) ?? "")
  330. if (user.firstName + " " + user.lastName).trimmingCharacters(in: .whitespaces) == "USR\(user.pin)" {
  331. continue
  332. }
  333. user.official = cursorData.string(forColumnIndex: 4) ?? ""
  334. if !self.contacts.contains(where: {$0.pin == user.pin}) {
  335. self.contacts.append(user)
  336. }
  337. }
  338. cursorData.close()
  339. }
  340. completion()
  341. })
  342. }
  343. }
  344. private func getGroupRecursive(fmdb: FMDatabase, id: String = "", parent: String = "") -> [Group] {
  345. var data: [Group] = []
  346. var query = "select g.group_id, g.f_name, g.image_id, g.quote, g.created_by, g.created_date, g.parent, g.group_type, g.is_open, g.official, g.is_education, g.level from GROUPZ g where "
  347. if id.isEmpty {
  348. query += "g.parent = '\(parent)'"
  349. } else {
  350. query += "g.group_id = '\(id)'"
  351. }
  352. query += "order by 10 desc"
  353. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: query) {
  354. while cursor.next() {
  355. let group = Group(
  356. id: cursor.string(forColumnIndex: 0) ?? "",
  357. name: cursor.string(forColumnIndex: 1) ?? "",
  358. profile: cursor.string(forColumnIndex: 2) ?? "",
  359. quote: cursor.string(forColumnIndex: 3) ?? "",
  360. by: cursor.string(forColumnIndex: 4) ?? "",
  361. date: cursor.string(forColumnIndex: 5) ?? "",
  362. parent: cursor.string(forColumnIndex: 6) ?? "",
  363. chatId: "",
  364. groupType: cursor.string(forColumnIndex: 7) ?? "",
  365. isOpen: cursor.string(forColumnIndex: 8) ?? "",
  366. official: cursor.string(forColumnIndex: 9) ?? "",
  367. isEducation: cursor.string(forColumnIndex: 10) ?? "",
  368. level: cursor.string(forColumnIndex: 11) ?? "")
  369. if group.chatId.isEmpty {
  370. let lounge = Group(id: group.id, name: "Lounge".localized(), profile: "", quote: group.quote, by: group.by, date: group.date, parent: group.id, chatId: group.chatId, groupType: group.groupType, isOpen: group.isOpen, official: group.official, isEducation: group.isEducation, isLounge: true, level: group.level != "-1" ? group.level : "2")
  371. group.childs.append(lounge)
  372. }
  373. if let topicCursor = Database.shared.getRecords(fmdb: fmdb, query: "select chat_id, title, thumb from DISCUSSION_FORUM where group_id = '\(group.id)'") {
  374. while topicCursor.next() {
  375. let topic = Group(id: group.id,
  376. name: topicCursor.string(forColumnIndex: 1) ?? "",
  377. profile: topicCursor.string(forColumnIndex: 2) ?? "",
  378. quote: group.quote,
  379. by: group.by,
  380. date: group.date,
  381. parent: group.id,
  382. chatId: topicCursor.string(forColumnIndex: 0) ?? "",
  383. groupType: group.groupType,
  384. isOpen: group.isOpen,
  385. official: group.official,
  386. isEducation: group.isEducation,
  387. level: group.level != "-1" ? group.level : "2")
  388. group.childs.append(topic)
  389. }
  390. topicCursor.close()
  391. }
  392. if !group.id.isEmpty {
  393. // if group.official == "1" {
  394. // let idMe = UserDefaults.standard.string(forKey: "me") as String?
  395. // if let cursorUser = Database.shared.getRecords(fmdb: fmdb, query: "SELECT user_type FROM BUDDY where f_pin='\(idMe!)'"), cursorUser.next() {
  396. //// if cursorUser.string(forColumnIndex: 0) == "23" || cursorUser.string(forColumnIndex: 0) == "24" {
  397. //// group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
  398. //// }
  399. // group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
  400. // cursorUser.close()
  401. // }
  402. // } else if group.official != "1"{
  403. // group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
  404. // }
  405. group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
  406. // group.childs = group.childs.sorted(by: { $0.name < $1.name })
  407. // let dataLounge = group.childs.filter({$0.name == "Lounge".localized()})
  408. // group.childs = group.childs.filter({ $0.name != "Lounge".localized() })
  409. // group.childs.insert(contentsOf: dataLounge, at: 0)
  410. }
  411. data.append(group)
  412. }
  413. cursor.close()
  414. }
  415. return data
  416. }
  417. private func getOpenGroups(listGroups: [Group], completion: @escaping ([Group]) -> ()) {
  418. if let response = DigiX.writeSync(message: CoreMessage_TMessageBank.getOpenGroups(p_account: "1,2,3,5,6,7", offset: "0", search: "")) {
  419. var dataGroups: [Group] = []
  420. if (response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "00") {
  421. let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
  422. if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [[String: Any?]] {
  423. for dataJson in json {
  424. let group = Group(
  425. id: dataJson[CoreMessage_TMessageKey.GROUP_ID] as? String ?? "",
  426. name: dataJson[CoreMessage_TMessageKey.GROUP_NAME] as? String ?? "",
  427. profile: dataJson[CoreMessage_TMessageKey.THUMB_ID] as? String ?? "",
  428. quote: dataJson[CoreMessage_TMessageKey.QUOTE] as? String ?? "",
  429. by: dataJson[CoreMessage_TMessageKey.BLOCK] as? String ?? "",
  430. date: "",
  431. parent: "",
  432. chatId: "",
  433. groupType: "NOTJOINED",
  434. isOpen: dataJson[CoreMessage_TMessageKey.IS_OPEN] as? String ?? "",
  435. official: "0",
  436. isEducation: "")
  437. dataGroups.append(group)
  438. }
  439. }
  440. } else {
  441. DispatchQueue.main.async {
  442. self.groups.removeAll()
  443. self.groups.append(contentsOf: listGroups)
  444. self.tableView.reloadData()
  445. }
  446. }
  447. completion(dataGroups)
  448. }
  449. }
  450. private func getGroups(id: String = "", parent: String = "", completion: @escaping ([Group]) -> ()) {
  451. DispatchQueue.global().async {
  452. Database.shared.database?.inTransaction({ fmdb, rollback in
  453. completion(self.getGroupRecursive(fmdb: fmdb, id: id, parent: parent))
  454. })
  455. }
  456. }
  457. private func pullBuddy() {
  458. if let me = UserDefaults.standard.string(forKey: "me") {
  459. DispatchQueue.global().async {
  460. let _ = DigiX.write(message: CoreMessage_TMessageBank.getBatchBuddiesInfos(p_f_pin: me, last_update: 0))
  461. }
  462. }
  463. }
  464. private func joinOpenGroup(groupId: String, flagMember: String = "0", completion: @escaping (Bool) -> ()) {
  465. DispatchQueue.global().async {
  466. var result: Bool = false
  467. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  468. if let response = DigiX.writeAndWait(message: CoreMessage_TMessageBank.getAddGroupMember(p_group_id: groupId, p_member_pin: idMe!, p_position: "0")), response.isOk() {
  469. result = true
  470. }
  471. completion(result)
  472. }
  473. }
  474. }
  475. // MARK: - Table view data source
  476. extension ContactChatViewController {
  477. override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  478. if noData {
  479. return
  480. }
  481. tableView.deselectRow(at: indexPath, animated: true)
  482. func selectOnContact() {
  483. let data: User
  484. if isFilltering {
  485. data = fillteredData[indexPath.row] as! User
  486. } else {
  487. data = contacts[indexPath.row]
  488. }
  489. if let chooser = isChooser {
  490. var exblock = User.getDataCanNil(pin: data.pin)?.ex_block
  491. exblock = exblock == nil ? "0" : exblock!.isEmpty ? "0" : exblock!
  492. if exblock != "0" {
  493. if exblock == "1" {
  494. self.view.makeToast("You blocked this user".localized())
  495. } else {
  496. self.view.makeToast("You have been blocked by this user".localized())
  497. }
  498. return
  499. }
  500. chooser("3", data.pin)
  501. dismiss(animated: true, completion: nil)
  502. return
  503. }
  504. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  505. editorPersonalVC.hidesBottomBarWhenPushed = true
  506. editorPersonalVC.unique_l_pin = data.pin
  507. navigationController?.show(editorPersonalVC, sender: nil)
  508. }
  509. if segment.numberOfSegments == 3 {
  510. switch segment.selectedSegmentIndex {
  511. case 0:
  512. let data: Chat
  513. if isFilltering {
  514. data = fillteredData[indexPath.row] as! Chat
  515. } else {
  516. data = chats[indexPath.row]
  517. }
  518. if let chooser = isChooser {
  519. var exblock = User.getDataCanNil(pin: data.pin)?.ex_block
  520. exblock = exblock == nil ? "0" : exblock!.isEmpty ? "0" : exblock!
  521. if exblock != "0" {
  522. if exblock == "1" {
  523. self.view.makeToast("You blocked this user".localized())
  524. } else {
  525. self.view.makeToast("You have been blocked by this user".localized())
  526. }
  527. return
  528. }
  529. if data.pin == "-999"{
  530. return
  531. }
  532. chooser(data.messageScope, data.pin)
  533. dismiss(animated: true, completion: nil)
  534. return
  535. }
  536. if data.messageScope == "3" {
  537. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  538. editorPersonalVC.hidesBottomBarWhenPushed = true
  539. editorPersonalVC.unique_l_pin = data.pin
  540. navigationController?.show(editorPersonalVC, sender: nil)
  541. } else {
  542. groupMap.removeAll()
  543. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  544. editorGroupVC.hidesBottomBarWhenPushed = true
  545. editorGroupVC.unique_l_pin = data.pin
  546. navigationController?.show(editorGroupVC, sender: nil)
  547. }
  548. case 1:
  549. selectOnContact()
  550. case 2:
  551. expandCollapseGroup(tableView: tableView, indexPath: indexPath)
  552. default:
  553. let data = contacts[indexPath.row]
  554. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  555. editorPersonalVC.hidesBottomBarWhenPushed = true
  556. editorPersonalVC.unique_l_pin = data.pin
  557. navigationController?.show(editorPersonalVC, sender: nil)
  558. }
  559. } else {
  560. switch segment.selectedSegmentIndex {
  561. case 0:
  562. selectOnContact()
  563. case 1:
  564. expandCollapseGroup(tableView: tableView, indexPath: indexPath)
  565. default:
  566. let data = contacts[indexPath.row]
  567. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  568. editorPersonalVC.hidesBottomBarWhenPushed = true
  569. editorPersonalVC.unique_l_pin = data.pin
  570. navigationController?.show(editorPersonalVC, sender: nil)
  571. }
  572. }
  573. }
  574. func expandCollapseGroup(tableView: UITableView, indexPath: IndexPath) {
  575. let group: Group
  576. if isFilltering {
  577. if indexPath.row == 0 {
  578. group = fillteredData[indexPath.section] as! Group
  579. } else {
  580. group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
  581. }
  582. } else {
  583. if indexPath.row == 0 {
  584. group = groups[indexPath.section]
  585. } else {
  586. group = groups[indexPath.section].childs[indexPath.row - 1]
  587. }
  588. }
  589. group.isSelected = !group.isSelected
  590. if !group.isSelected{
  591. var sects = 0
  592. var sect = indexPath.section
  593. var id = group.id
  594. if let _ = groupMap[id] {
  595. var loooop = true
  596. repeat {
  597. let c = sect + 1
  598. if isFilltering {
  599. if let o = self.fillteredData[c] as? Group {
  600. if o.parent == id {
  601. sects = sects + 1
  602. sect = c
  603. id = o.id
  604. (self.fillteredData[c] as! Group).isSelected = false
  605. self.groupMap.removeValue(forKey: (self.fillteredData[c] as! Group).id)
  606. }
  607. else {
  608. loooop = false
  609. }
  610. }
  611. }
  612. else {
  613. if c < self.groups.count && self.groups[c].parent == id {
  614. sects = sects + 1
  615. sect = c
  616. id = self.groups[c].id
  617. self.groups[c].isSelected = false
  618. self.groupMap.removeValue(forKey: self.groups[c].id)
  619. }
  620. else {
  621. loooop = false
  622. }
  623. }
  624. } while(loooop)
  625. }
  626. for i in stride(from: sects, to: 0, by: -1){
  627. if isFilltering {
  628. self.fillteredData.remove(at: indexPath.section + i)
  629. }
  630. else {
  631. self.groups.remove(at: indexPath.section + i)
  632. }
  633. }
  634. groupMap.removeValue(forKey: group.id)
  635. }
  636. if group.groupType == "NOTJOINED" {
  637. let alert = LibAlertController(title: "Do you want to join this group?".localized(), message: "Groups : \(group.name)\nMembers: \(group.by)".localized(), preferredStyle: .alert)
  638. alert.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
  639. alert.addAction(UIAlertAction(title: "Join".localized(), style: .default, handler: {(_) in
  640. self.joinOpenGroup(groupId: group.id, completion: { result in
  641. if result {
  642. DispatchQueue.main.async {
  643. self.groupMap.removeAll()
  644. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  645. editorGroupVC.hidesBottomBarWhenPushed = true
  646. editorGroupVC.unique_l_pin = group.id
  647. self.navigationController?.show(editorGroupVC, sender: nil)
  648. }
  649. }
  650. })
  651. }))
  652. self.present(alert, animated: true, completion: nil)
  653. return
  654. }
  655. if group.childs.count == 0 {
  656. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  657. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  658. if let cursorMember = Database.shared.getRecords(fmdb: fmdb, query: "select f_pin from GROUPZ_MEMBER where group_id = '\(group.id)' and f_pin = '\(idMe!)'"), cursorMember.next() {
  659. let groupId = group.chatId.isEmpty ? group.id : group.chatId
  660. if let chooser = isChooser {
  661. chooser("4", groupId)
  662. dismiss(animated: true, completion: nil)
  663. return
  664. }
  665. self.groupMap.removeAll()
  666. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  667. editorGroupVC.hidesBottomBarWhenPushed = true
  668. editorGroupVC.unique_l_pin = groupId
  669. navigationController?.show(editorGroupVC, sender: nil)
  670. cursorMember.close()
  671. } else {
  672. self.view.makeToast("You are not a member of this group".localized(), duration: 0.5)
  673. }
  674. })
  675. } else {
  676. if indexPath.row == 0 {
  677. tableView.reloadData()
  678. } else {
  679. getGroups(id: group.id) { g in
  680. DispatchQueue.main.async {
  681. //print(("index path section: \(indexPath.section)")
  682. //print(("index path row: \(indexPath.row)")
  683. // //print(("index path item: \(indexPath.item)")
  684. if self.isFilltering {
  685. // self.fillteredData.remove(at: indexPath.section)
  686. if self.fillteredData[indexPath.section] is Group {
  687. self.groupMap[(self.fillteredData[indexPath.section] as! Group).id] = 1
  688. self.fillteredData.insert(contentsOf: g, at: indexPath.section + 1)
  689. }
  690. } else {
  691. // self.groups.remove(at: indexPath.section)
  692. self.groupMap[self.groups[indexPath.section].id] = 1
  693. self.groups.insert(contentsOf: g, at: indexPath.section + 1)
  694. }
  695. //print(("groupMap: \(self.groupMap)")
  696. tableView.reloadData()
  697. self.expandCollapseGroup(tableView: tableView, indexPath: IndexPath(row: 0, section: indexPath.section + 1))
  698. }
  699. }
  700. }
  701. }
  702. }
  703. }
  704. extension ContactChatViewController {
  705. override func numberOfSections(in tableView: UITableView) -> Int {
  706. if isFilltering {
  707. if ((segment.numberOfSegments == 3 && segment.selectedSegmentIndex == 2) || (segment.numberOfSegments < 3 && segment.selectedSegmentIndex == 1)) {
  708. return fillteredData.count
  709. }
  710. return 1
  711. } else {
  712. if ((segment.numberOfSegments == 3 && segment.selectedSegmentIndex == 2) || (segment.numberOfSegments < 3 && segment.selectedSegmentIndex == 1)) {
  713. return groups.count
  714. }
  715. return 1
  716. }
  717. }
  718. override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  719. var value = 0
  720. if isFilltering {
  721. func filterGroup(groups: [Group]) {
  722. let group = groups[section]
  723. if group.isSelected {
  724. if let _ = groupMap[group.id] {
  725. value = 1
  726. }
  727. else {
  728. value = group.childs.count + 1
  729. }
  730. } else {
  731. value = 1
  732. }
  733. }
  734. if ((segment.numberOfSegments == 3 && segment.selectedSegmentIndex == 2) || (segment.numberOfSegments < 3 && segment.selectedSegmentIndex == 1)), let groups = fillteredData as? [Group] {
  735. filterGroup(groups: groups)
  736. } else {
  737. value = fillteredData.count
  738. }
  739. return value
  740. }
  741. if segment.numberOfSegments == 3 {
  742. switch segment.selectedSegmentIndex {
  743. case 0:
  744. value = chats.count
  745. case 1:
  746. value = contacts.count
  747. case 2:
  748. let group = groups[section]
  749. if group.isSelected {
  750. if let _ = groupMap[group.id] {
  751. value = 1
  752. }
  753. else {
  754. value = group.childs.count + 1
  755. }
  756. } else {
  757. value = 1
  758. }
  759. default:
  760. value = chats.count
  761. }
  762. } else {
  763. switch segment.selectedSegmentIndex {
  764. case 0:
  765. value = contacts.count
  766. case 1:
  767. let group = groups[section]
  768. if group.isSelected {
  769. if let _ = groupMap[group.id] {
  770. value = 1
  771. }
  772. else {
  773. value = group.childs.count + 1
  774. }
  775. } else {
  776. value = 1
  777. }
  778. default:
  779. value = chats.count
  780. }
  781. }
  782. if value == 0 {
  783. noData = true
  784. value = 1
  785. tableView.separatorStyle = .none
  786. } else {
  787. noData = false
  788. tableView.separatorStyle = .singleLine
  789. }
  790. return value
  791. }
  792. override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  793. var cell: UITableViewCell!
  794. switch segment.selectedSegmentIndex {
  795. case 0:
  796. if segment.numberOfSegments < 3 {
  797. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierContact", for: indexPath)
  798. var content = cell.defaultContentConfiguration()
  799. let data: User
  800. if isFilltering {
  801. data = fillteredData[indexPath.row] as! User
  802. } else {
  803. if indexPath.row > contacts.count - 1 {
  804. return cell
  805. }
  806. data = contacts[indexPath.row]
  807. }
  808. content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
  809. getImage(name: data.thumb, placeholderImage: UIImage(named: "Profile---Purple", in: Bundle.resourceBundle(for: DigiX.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
  810. content.image = image
  811. })
  812. if User.isOfficial(official_account: data.official ?? "") || User.isOfficialRegular(official_account: data.official ?? "") {
  813. content.attributedText = self.set(image: UIImage(named: "ic_official_flag", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.officialColor)
  814. } else if User.isVerified(official_account: data.official ?? "") {
  815. content.attributedText = self.set(image: UIImage(named: "ic_verified", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.verifiedColor)
  816. }
  817. else if User.isInternal(userType: data.userType ?? "") {
  818. content.attributedText = self.set(image: UIImage(named: "ic_internal", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.internalColor)
  819. } else if User.isCallCenter(userType: data.userType ?? "") {
  820. // let dataCategory = CategoryCC.getDataFromServiceId(service_id: data.ex_offmp!)
  821. // if dataCategory != nil {
  822. // content.attributedText = self.set(image: UIImage(named: "pb_call_center", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName) (\(dataCategory!.service_name))", size: 15, y: -4, colorText: UIColor.ccColor)
  823. // } else {
  824. content.attributedText = self.set(image: UIImage(named: "pb_call_center", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.ccColor)
  825. // }
  826. } else {
  827. content.text = data.fullName
  828. }
  829. content.textProperties.font = UIFont.systemFont(ofSize: 14)
  830. cell.contentConfiguration = content
  831. } else {
  832. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierChat", for: indexPath)
  833. let content = cell.contentView
  834. if content.subviews.count > 0 {
  835. content.subviews.forEach { $0.removeFromSuperview() }
  836. }
  837. if noData {
  838. let labelNochat = UILabel()
  839. labelNochat.text = "There are no conversations".localized()
  840. labelNochat.font = .systemFont(ofSize: 13)
  841. labelNochat.textColor = .black
  842. content.addSubview(labelNochat)
  843. labelNochat.anchor(centerX: content.centerXAnchor, centerY: content.centerYAnchor)
  844. cell.backgroundColor = .clear
  845. cell.selectionStyle = .none
  846. return cell
  847. }
  848. let data: Chat
  849. if isFilltering {
  850. data = fillteredData[indexPath.row] as! Chat
  851. } else {
  852. if chats.count == 0 {
  853. let labelNochat = UILabel()
  854. labelNochat.text = "There are no conversations".localized()
  855. labelNochat.font = .systemFont(ofSize: 13)
  856. labelNochat.textColor = .black
  857. content.addSubview(labelNochat)
  858. labelNochat.anchor(centerX: content.centerXAnchor, centerY: content.centerYAnchor)
  859. cell.backgroundColor = .clear
  860. cell.selectionStyle = .none
  861. return cell
  862. }
  863. data = chats[indexPath.row]
  864. }
  865. let imageView = UIImageView()
  866. content.addSubview(imageView)
  867. imageView.translatesAutoresizingMaskIntoConstraints = false
  868. NSLayoutConstraint.activate([
  869. imageView.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 10.0),
  870. imageView.topAnchor.constraint(equalTo: content.topAnchor, constant: 10.0),
  871. imageView.bottomAnchor.constraint(equalTo: content.bottomAnchor, constant: -10.0),
  872. imageView.widthAnchor.constraint(equalToConstant: 55.0),
  873. imageView.heightAnchor.constraint(equalToConstant: 55.0)
  874. ])
  875. if data.profile.isEmpty && data.pin != "-999" {
  876. if data.messageScope == "3" {
  877. imageView.image = UIImage(named: "Profile---Purple", in: Bundle.resourceBundle(for: DigiX.self), with: nil)
  878. } else {
  879. imageView.image = UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: DigiX.self), with: nil)
  880. }
  881. } else {
  882. if Utils.getIconDock() != nil {
  883. let dataImage = try? Data(contentsOf: URL(string: Utils.getUrlDock()!)!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
  884. if dataImage != nil {
  885. getImage(name: data.profile, placeholderImage: UIImage(data: dataImage!), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
  886. imageView.image = image
  887. })
  888. }
  889. } else {
  890. getImage(name: data.profile, placeholderImage: UIImage(named: data.pin == "-999" ? "pb_button" : data.messageScope == "3" ? "Profile---Purple" : "Conversation---Purple", in: Bundle.resourceBundle(for: DigiX.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
  891. imageView.image = image
  892. })
  893. }
  894. }
  895. let titleView = UILabel()
  896. content.addSubview(titleView)
  897. titleView.translatesAutoresizingMaskIntoConstraints = false
  898. NSLayoutConstraint.activate([
  899. titleView.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10.0),
  900. titleView.topAnchor.constraint(equalTo: content.topAnchor, constant: 10.0),
  901. titleView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
  902. ])
  903. titleView.text = data.name
  904. titleView.font = UIFont.systemFont(ofSize: 14, weight: .medium)
  905. let messageView = UILabel()
  906. content.addSubview(messageView)
  907. messageView.translatesAutoresizingMaskIntoConstraints = false
  908. NSLayoutConstraint.activate([
  909. messageView.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10.0),
  910. messageView.topAnchor.constraint(equalTo: titleView.bottomAnchor, constant: 5.0),
  911. messageView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
  912. ])
  913. messageView.textColor = .gray
  914. let text = Utils.previewMessageText(chat: data)
  915. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  916. if let attributeText = text as? NSMutableAttributedString {
  917. if data.fpin == idMe {
  918. if data.lock == "1" {
  919. messageView.attributedText = ("🚫 _"+"You were deleted this message".localized()+"_").richText()
  920. } else {
  921. let stringMessage = NSMutableAttributedString(string: "")
  922. let imageStatus = NSTextAttachment()
  923. let status = getRealStatus(messageId: data.messageId)
  924. if (status == "1" || status == "2" ) {
  925. imageStatus.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!.withTintColor(UIColor.lightGray)
  926. } else if (status == "3") {
  927. imageStatus.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!.withTintColor(UIColor.lightGray)
  928. } else if (status == "8") {
  929. imageStatus.image = UIImage(named: "message_status_ack", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!.withRenderingMode(.alwaysOriginal)
  930. } else {
  931. imageStatus.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!.withTintColor(UIColor.systemBlue)
  932. }
  933. imageStatus.bounds = CGRect(x: 0, y: 0, width: 15, height: 15)
  934. let imageStatusString = NSAttributedString(attachment: imageStatus)
  935. stringMessage.append(imageStatusString)
  936. stringMessage.append(NSAttributedString(string: " "))
  937. stringMessage.append(attributeText)
  938. messageView.attributedText = stringMessage
  939. }
  940. } else {
  941. if data.lock == "1" {
  942. messageView.attributedText = ("🚫 _"+"This message was deleted".localized()+"_").richText()
  943. } else {
  944. messageView.attributedText = attributeText
  945. }
  946. }
  947. }
  948. messageView.numberOfLines = 2
  949. let timeView = UILabel()
  950. content.addSubview(timeView)
  951. timeView.translatesAutoresizingMaskIntoConstraints = false
  952. NSLayoutConstraint.activate([
  953. timeView.topAnchor.constraint(equalTo: content.topAnchor, constant: 10.0),
  954. timeView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -20.0),
  955. ])
  956. timeView.textColor = .gray
  957. timeView.font = UIFont.systemFont(ofSize: 14)
  958. let date = Date(milliseconds: Int64(data.serverDate)!)
  959. let calendar = Calendar.current
  960. if (calendar.isDateInToday(date)) {
  961. let formatter = DateFormatter()
  962. formatter.dateFormat = "HH:mm"
  963. formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
  964. timeView.text = formatter.string(from: date as Date)
  965. } else {
  966. let startOfNow = calendar.startOfDay(for: Date())
  967. let startOfTimeStamp = calendar.startOfDay(for: date)
  968. let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
  969. let day = -(components.day!)
  970. if day == 1 {
  971. timeView.text = "Yesterday".localized()
  972. } else {
  973. if day < 7 {
  974. let formatter = DateFormatter()
  975. formatter.dateFormat = "EEEE"
  976. timeView.text = formatter.string(from: date)
  977. } else {
  978. let formatter = DateFormatter()
  979. formatter.dateFormat = "MM/dd/yy"
  980. formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
  981. let stringFormat = formatter.string(from: date as Date)
  982. timeView.text = stringFormat
  983. }
  984. }
  985. }
  986. if data.counter != "0" {
  987. timeView.textColor = .systemRed
  988. let viewCounter = UIView()
  989. content.addSubview(viewCounter)
  990. viewCounter.translatesAutoresizingMaskIntoConstraints = false
  991. NSLayoutConstraint.activate([
  992. viewCounter.topAnchor.constraint(equalTo: timeView.bottomAnchor, constant: 5.0),
  993. viewCounter.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -20),
  994. viewCounter.widthAnchor.constraint(greaterThanOrEqualToConstant: 20),
  995. viewCounter.heightAnchor.constraint(equalToConstant: 20)
  996. ])
  997. viewCounter.backgroundColor = .systemRed
  998. viewCounter.layer.cornerRadius = 10
  999. viewCounter.clipsToBounds = true
  1000. viewCounter.layer.borderWidth = 0.5
  1001. viewCounter.layer.borderColor = UIColor.secondaryColor.cgColor
  1002. let labelCounter = UILabel()
  1003. viewCounter.addSubview(labelCounter)
  1004. labelCounter.translatesAutoresizingMaskIntoConstraints = false
  1005. NSLayoutConstraint.activate([
  1006. labelCounter.centerYAnchor.constraint(equalTo: viewCounter.centerYAnchor),
  1007. labelCounter.leadingAnchor.constraint(equalTo: viewCounter.leadingAnchor, constant: 2),
  1008. labelCounter.trailingAnchor.constraint(equalTo: viewCounter.trailingAnchor, constant: -2),
  1009. ])
  1010. labelCounter.font = UIFont.systemFont(ofSize: 11)
  1011. if Int(data.counter)! > 99 {
  1012. labelCounter.text = "99+"
  1013. } else {
  1014. labelCounter.text = data.counter
  1015. }
  1016. labelCounter.textColor = .secondaryColor
  1017. labelCounter.textAlignment = .center
  1018. }
  1019. }
  1020. case 1:
  1021. if segment.numberOfSegments < 3 {
  1022. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierGroup", for: indexPath)
  1023. var content = cell.defaultContentConfiguration()
  1024. content.textProperties.font = UIFont.systemFont(ofSize: 14)
  1025. let group: Group
  1026. if isFilltering {
  1027. if indexPath.row == 0 {
  1028. group = fillteredData[indexPath.section] as! Group
  1029. } else {
  1030. if (fillteredData[indexPath.section] as! Group).childs.count > 0 {
  1031. group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
  1032. } else {
  1033. return cell
  1034. }
  1035. }
  1036. } else {
  1037. if indexPath.row == 0 {
  1038. if indexPath.section > (groups.count - 1) {
  1039. return cell
  1040. }
  1041. group = groups[indexPath.section]
  1042. } else {
  1043. group = groups[indexPath.section].childs[indexPath.row - 1]
  1044. }
  1045. }
  1046. if group.official == "1" && group.parent == "" {
  1047. content.attributedText = self.set(image: UIImage(named: "ic_official_flag", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(group.name)", size: 15, y: -4)
  1048. }
  1049. else if group.isOpen == "1" && group.parent == "" {
  1050. if self.traitCollection.userInterfaceStyle == .dark {
  1051. content.attributedText = self.set(image: UIImage(systemName: "globe")!.withTintColor(.white), with: " \(group.name)", size: 15, y: -4)
  1052. } else {
  1053. content.attributedText = self.set(image: UIImage(systemName: "globe")!, with: " \(group.name)", size: 15, y: -4)
  1054. }
  1055. } else if group.parent == "" {
  1056. if self.traitCollection.userInterfaceStyle == .dark {
  1057. content.attributedText = self.set(image: UIImage(systemName: "lock.fill")!.withTintColor(.white), with: " \(group.name)", size: 15, y: -4)
  1058. } else {
  1059. content.attributedText = self.set(image: UIImage(systemName: "lock.fill")!, with: " \(group.name)", size: 15, y: -4)
  1060. }
  1061. } else {
  1062. content.text = group.name
  1063. }
  1064. if group.childs.count > 0 {
  1065. let iconName = (group.isSelected) ? "chevron.up.circle" : "chevron.down.circle"
  1066. let imageView = UIImageView(image: UIImage(systemName: iconName))
  1067. imageView.tintColor = .black
  1068. cell.accessoryView = imageView
  1069. }
  1070. else {
  1071. cell.accessoryView = nil
  1072. cell.accessoryType = .none
  1073. }
  1074. content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
  1075. getImage(name: group.profile, placeholderImage: UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: DigiX.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath) { result, isDownloaded, image in
  1076. content.image = image
  1077. }
  1078. cell.contentConfiguration = content
  1079. if !group.level.isEmpty {
  1080. if group.level != "-1" && Int(group.level)! < 7 {
  1081. cell.contentView.layoutMargins = .init(top: 0.0, left: CGFloat(25 * Int(group.level)!), bottom: 0.0, right: 0)
  1082. } else if Int(group.level)! > 6 {
  1083. cell.contentView.layoutMargins = .init(top: 0.0, left: CGFloat(25 * (Int(group.level)! - 6)), bottom: 0.0, right: 0)
  1084. }
  1085. }
  1086. } else {
  1087. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierContact", for: indexPath)
  1088. var content = cell.defaultContentConfiguration()
  1089. let data: User
  1090. if isFilltering {
  1091. data = fillteredData[indexPath.row] as! User
  1092. } else {
  1093. if indexPath.row > contacts.count - 1 {
  1094. return cell
  1095. }
  1096. data = contacts[indexPath.row]
  1097. }
  1098. content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
  1099. getImage(name: data.thumb, placeholderImage: UIImage(named: "Profile---Purple", in: Bundle.resourceBundle(for: DigiX.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
  1100. content.image = image
  1101. })
  1102. if User.isOfficial(official_account: data.official ?? "") || User.isOfficialRegular(official_account: data.official ?? "") {
  1103. content.attributedText = self.set(image: UIImage(named: "ic_official_flag", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.officialColor)
  1104. } else if User.isVerified(official_account: data.official ?? "") {
  1105. content.attributedText = self.set(image: UIImage(named: "ic_verified", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.verifiedColor)
  1106. }
  1107. else if User.isInternal(userType: data.userType ?? "") {
  1108. content.attributedText = self.set(image: UIImage(named: "ic_internal", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.internalColor)
  1109. } else if User.isCallCenter(userType: data.userType ?? "") {
  1110. // let dataCategory = CategoryCC.getDataFromServiceId(service_id: data.ex_offmp!)
  1111. // if dataCategory != nil {
  1112. // content.attributedText = self.set(image: UIImage(named: "pb_call_center", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName) (\(dataCategory!.service_name))", size: 15, y: -4, colorText: UIColor.ccColor)
  1113. // } else {
  1114. content.attributedText = self.set(image: UIImage(named: "pb_call_center", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.ccColor)
  1115. // }
  1116. } else {
  1117. content.text = data.fullName
  1118. }
  1119. content.textProperties.font = UIFont.systemFont(ofSize: 14)
  1120. cell.contentConfiguration = content
  1121. }
  1122. case 2:
  1123. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierGroup", for: indexPath)
  1124. var content = cell.defaultContentConfiguration()
  1125. content.textProperties.font = UIFont.systemFont(ofSize: 14)
  1126. let group: Group
  1127. if isFilltering {
  1128. if indexPath.row == 0 {
  1129. group = fillteredData[indexPath.section] as! Group
  1130. } else {
  1131. if (fillteredData[indexPath.section] as! Group).childs.count > 0 {
  1132. group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
  1133. } else {
  1134. return cell
  1135. }
  1136. }
  1137. } else {
  1138. if indexPath.row == 0 {
  1139. if indexPath.section > (groups.count - 1) {
  1140. return cell
  1141. }
  1142. group = groups[indexPath.section]
  1143. } else {
  1144. group = groups[indexPath.section].childs[indexPath.row - 1]
  1145. }
  1146. }
  1147. if group.official == "1" && group.parent == "" {
  1148. content.attributedText = self.set(image: UIImage(named: "ic_official_flag", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!, with: " \(group.name)", size: 15, y: -4)
  1149. }
  1150. else if group.isOpen == "1" && group.parent == "" {
  1151. if self.traitCollection.userInterfaceStyle == .dark {
  1152. content.attributedText = self.set(image: UIImage(systemName: "globe")!.withTintColor(.white), with: " \(group.name)", size: 15, y: -4)
  1153. } else {
  1154. content.attributedText = self.set(image: UIImage(systemName: "globe")!, with: " \(group.name)", size: 15, y: -4)
  1155. }
  1156. } else if group.parent == "" {
  1157. if self.traitCollection.userInterfaceStyle == .dark {
  1158. content.attributedText = self.set(image: UIImage(systemName: "lock.fill")!.withTintColor(.white), with: " \(group.name)", size: 15, y: -4)
  1159. } else {
  1160. content.attributedText = self.set(image: UIImage(systemName: "lock.fill")!, with: " \(group.name)", size: 15, y: -4)
  1161. }
  1162. } else {
  1163. content.text = group.name
  1164. }
  1165. if group.childs.count > 0 {
  1166. let iconName = (group.isSelected) ? "chevron.up.circle" : "chevron.down.circle"
  1167. let imageView = UIImageView(image: UIImage(systemName: iconName))
  1168. imageView.tintColor = .black
  1169. cell.accessoryView = imageView
  1170. }
  1171. else {
  1172. cell.accessoryView = nil
  1173. cell.accessoryType = .none
  1174. }
  1175. content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
  1176. getImage(name: group.profile, placeholderImage: UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: DigiX.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath) { result, isDownloaded, image in
  1177. content.image = image
  1178. }
  1179. cell.contentConfiguration = content
  1180. if !group.level.isEmpty {
  1181. if group.level != "-1" && Int(group.level)! < 7 {
  1182. cell.contentView.layoutMargins = .init(top: 0.0, left: CGFloat(25 * Int(group.level)!), bottom: 0.0, right: 0)
  1183. } else if Int(group.level)! > 6 {
  1184. cell.contentView.layoutMargins = .init(top: 0.0, left: CGFloat(25 * (Int(group.level)! - 6)), bottom: 0.0, right: 0)
  1185. }
  1186. }
  1187. default:
  1188. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierContact", for: indexPath)
  1189. var content = cell.defaultContentConfiguration()
  1190. content.text = ""
  1191. cell.contentConfiguration = content
  1192. }
  1193. cell.backgroundColor = .clear
  1194. cell.separatorInset = UIEdgeInsets(top: 0, left: 60.0, bottom: 0, right: 0)
  1195. return cell
  1196. }
  1197. override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  1198. return 75.0
  1199. }
  1200. private func getRealStatus(messageId: String) -> String {
  1201. var status = "1"
  1202. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1203. if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status, f_pin FROM MESSAGE_STATUS WHERE message_id='\(messageId)'") {
  1204. var listStatus: [Int] = []
  1205. while cursorStatus.next() {
  1206. listStatus.append(Int(cursorStatus.string(forColumnIndex: 0)!)!)
  1207. }
  1208. cursorStatus.close()
  1209. status = "\(listStatus.min() ?? 2)"
  1210. }
  1211. })
  1212. return status
  1213. }
  1214. }
  1215. extension ContactChatViewController: UISearchControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating {
  1216. func updateSearchResults(for searchController: UISearchController) {
  1217. filterContentForSearchText(searchController.searchBar.text!.trimmingCharacters(in: .whitespacesAndNewlines))
  1218. }
  1219. func set(image: UIImage, with text: String, size: CGFloat, y: CGFloat, colorText: UIColor = UIColor.black) -> NSAttributedString {
  1220. let attachment = NSTextAttachment()
  1221. attachment.image = image
  1222. attachment.bounds = CGRect(x: 0, y: y, width: size, height: size)
  1223. let attachmentStr = NSAttributedString(attachment: attachment)
  1224. let mutableAttributedString = NSMutableAttributedString()
  1225. mutableAttributedString.append(attachmentStr)
  1226. let attributedStringColor = [NSAttributedString.Key.foregroundColor : colorText]
  1227. let textString = NSAttributedString(string: text, attributes: attributedStringColor)
  1228. mutableAttributedString.append(textString)
  1229. return mutableAttributedString
  1230. }
  1231. func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
  1232. searchBar.showsCancelButton = true
  1233. let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
  1234. cBtn.setTitle("Cancel".localized(), for: .normal)
  1235. }
  1236. func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
  1237. searchBar.showsCancelButton = false
  1238. }
  1239. }