ContactChatViewController.swift 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  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. func filterContentForSearchText(_ searchText: String) {
  33. switch segment.selectedSegmentIndex {
  34. case 1:
  35. fillteredData = self.contacts.filter { $0.fullName.lowercased().contains(searchText.lowercased()) }
  36. case 2:
  37. fillteredData = self.groups.filter { $0.name.lowercased().contains(searchText.lowercased()) }
  38. default:
  39. fillteredData = self.chats.filter { $0.name.lowercased().contains(searchText.lowercased()) || $0.messageText.lowercased().contains(searchText.lowercased()) }
  40. }
  41. tableView.reloadData()
  42. }
  43. override func viewDidLoad() {
  44. super.viewDidLoad()
  45. let me = UserDefaults.standard.string(forKey: "me")!
  46. Database.shared.database?.inTransaction({ fmdb, rollback in
  47. 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() {
  48. isAdmin = cursor.string(forColumnIndex: 3) == "23" || cursor.string(forColumnIndex: 3) == "24"
  49. cursor.close()
  50. }
  51. })
  52. // navigationController?.navigationBar.prefersLargeTitles = true
  53. navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel".localized(), style: .plain, target: self, action: #selector(cancel(sender:)))
  54. var childrenMenu : [UIAction] = [
  55. UIAction(title: "Create Group".localized(), image: UIImage(systemName: "person.and.person"), handler: {[weak self](_) in
  56. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "createGroupNav") as! UINavigationController
  57. let vc = controller.topViewController as! GroupCreateViewController
  58. vc.isDismiss = { id in
  59. self?.groupMap.removeAll()
  60. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "groupDetailView") as! GroupDetailViewController
  61. controller.data = id
  62. self?.navigationController?.show(controller, sender: nil)
  63. }
  64. self?.navigationController?.present(controller, animated: true, completion: nil)
  65. }),
  66. UIAction(title: "Add Friends".localized(), image: UIImage(systemName: "person.badge.plus"), handler: {[weak self](_) in
  67. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "addFriendNav") as! UINavigationController
  68. if let vc = controller.viewControllers.first as? AddFriendTableViewController {
  69. vc.isDismiss = {
  70. self?.getContacts {
  71. DispatchQueue.main.async {
  72. self?.tableView.reloadData()
  73. }
  74. }
  75. }
  76. }
  77. self?.navigationController?.present(controller, animated: true, completion: nil)
  78. }),
  79. // UIAction(title: "Configure Email", image: UIImage(systemName: "mail"), handler: {[weak self](_) in
  80. //
  81. // }),
  82. UIAction(title: "Favorite Messages".localized(), image: UIImage(systemName: "star"), handler: {[weak self](_) in
  83. let editorStaredVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "staredVC") as! EditorStarMessages
  84. self?.navigationController?.show(editorStaredVC, sender: nil)
  85. }),
  86. ]
  87. //debug only
  88. // isAdmin = true
  89. // if(isAdmin){
  90. // childrenMenu.append(UIAction(title: "Broadcast Message".localized(), image: UIImage(systemName: "envelope.open"), handler: {[weak self](_) in
  91. // let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "broadcastNav")
  92. // controller.modalPresentationStyle = .fullScreen
  93. // self?.navigationController?.present(controller, animated: true, completion: nil)
  94. // }))
  95. // childrenMenu.append(UIAction(title: "Live Streaming".localized(), image: UIImage(systemName: "video.bubble.left"), handler: {[weak self](_) in
  96. // let navigationController = UINavigationController(rootViewController: QmeraCreateStreamingViewController())
  97. // navigationController.modalPresentationStyle = .fullScreen
  98. // navigationController.navigationBar.tintColor = .white
  99. // navigationController.navigationBar.barTintColor = .mainColor
  100. // navigationController.navigationBar.isTranslucent = false
  101. // navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  102. // navigationController.navigationBar.barStyle = .black
  103. // let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white]
  104. // UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  105. // let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  106. // navigationController.navigationBar.titleTextAttributes = textAttributes
  107. // navigationController.view.backgroundColor = .mainColor
  108. // self?.navigationController?.present(navigationController, animated: true, completion: nil)
  109. // }))
  110. // }
  111. let menu = UIMenu(title: "", children: childrenMenu)
  112. navigationItem.rightBarButtonItem = UIBarButtonItem(title: nil, image: UIImage(systemName: "ellipsis"), primaryAction: .none, menu: menu)
  113. searchController = UISearchController(searchResultsController: nil)
  114. searchController.delegate = self
  115. searchController.searchResultsUpdater = self
  116. searchController.searchBar.autocapitalizationType = .none
  117. searchController.searchBar.delegate = self
  118. searchController.searchBar.barTintColor = .secondaryColor
  119. searchController.searchBar.searchTextField.backgroundColor = .secondaryColor
  120. searchController.obscuresBackgroundDuringPresentation = false
  121. searchController.searchBar.setMagnifyingGlassColorTo(color: .mainColor)
  122. searchController.searchBar.tintColor = .mainColor
  123. searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Search".localized(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray])
  124. navigationItem.searchController = searchController
  125. navigationItem.hidesSearchBarWhenScrolling = false
  126. definesPresentationContext = true
  127. segment = UISegmentedControl(items: ["Chats".localized(), "Contacts".localized(), "Groups".localized()])
  128. segment.sizeToFit()
  129. segment.selectedSegmentIndex = 0
  130. segment.addTarget(self, action: #selector(segmentChanged(sender:)), for: .valueChanged)
  131. segment.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 12.0)], for: .normal)
  132. NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
  133. NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
  134. NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onMember"), object: nil)
  135. NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil)
  136. tableView.tableHeaderView = segment
  137. tableView.tableFooterView = UIView()
  138. pullBuddy()
  139. }
  140. override func viewWillAppear(_ animated: Bool) {
  141. let attributes = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16.0), NSAttributedString.Key.foregroundColor: UIColor.white]
  142. let navBarAppearance = UINavigationBarAppearance()
  143. navBarAppearance.configureWithOpaqueBackground()
  144. navBarAppearance.backgroundColor = UIColor.mainColor
  145. navBarAppearance.titleTextAttributes = attributes
  146. navigationController?.navigationBar.standardAppearance = navBarAppearance
  147. navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
  148. // removeAllData()
  149. getData()
  150. }
  151. override func viewDidAppear(_ animated: Bool) {
  152. if isChooser != nil {
  153. self.navigationController?.navigationBar.topItem?.title = "Forward Messages".localized()
  154. self.navigationController?.navigationBar.setNeedsLayout()
  155. } else {
  156. self.navigationController?.navigationBar.topItem?.title = "Start Conversation".localized()
  157. self.navigationController?.navigationBar.setNeedsLayout()
  158. }
  159. DispatchQueue.global().async {
  160. self.getOpenGroups(listGroups: self.groups, completion: { g in
  161. DispatchQueue.main.async {
  162. for og in g {
  163. if self.groups.first(where: { $0.id == og.id }) == nil {
  164. self.groups.append(og)
  165. }
  166. }
  167. DispatchQueue.main.async {
  168. self.tableView.reloadData()
  169. }
  170. }
  171. })
  172. }
  173. }
  174. // func removeAllData() {
  175. // groups.removeAll()
  176. // groupMap.removeAll()
  177. // chats.removeAll()
  178. // tableView.reloadData()
  179. // }
  180. @objc func onReload(notification: NSNotification) {
  181. let data:[AnyHashable : Any] = notification.userInfo!
  182. if data["member"] as? String == UserDefaults.standard.string(forKey: "me") {
  183. DispatchQueue.main.async {
  184. self.getData()
  185. }
  186. } else if data["state"] as? Int == 99 {
  187. print("MASUK 99")
  188. DispatchQueue.main.async {
  189. self.getData()
  190. }
  191. }
  192. }
  193. @objc func onReceiveMessage(notification: NSNotification) {
  194. self.getChats {
  195. DispatchQueue.main.async {
  196. self.tableView.reloadData()
  197. }
  198. }
  199. }
  200. @objc func add(sender: Any) {
  201. }
  202. @objc func cancel(sender: Any) {
  203. navigationController?.dismiss(animated: true, completion: nil)
  204. }
  205. @objc func segmentChanged(sender: Any) {
  206. filterContentForSearchText(searchController.searchBar.text!)
  207. }
  208. // MARK: - Data source
  209. func getData() {
  210. getChats {
  211. self.getContacts {
  212. self.getGroups { g1 in
  213. self.groupMap.removeAll()
  214. self.groups = g1
  215. DispatchQueue.main.async {
  216. self.tableView.reloadData()
  217. }
  218. }
  219. }
  220. }
  221. }
  222. func getChats(completion: @escaping ()->()) {
  223. DispatchQueue.global().async {
  224. self.chats = Chat.getData()
  225. completion()
  226. }
  227. }
  228. private func getContacts(completion: @escaping ()->()) {
  229. self.contacts.removeAll()
  230. DispatchQueue.global().async {
  231. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  232. 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") {
  233. while cursorData.next() {
  234. let user = User(pin: cursorData.string(forColumnIndex: 0) ?? "",
  235. firstName: cursorData.string(forColumnIndex: 1) ?? "",
  236. lastName: cursorData.string(forColumnIndex: 2) ?? "",
  237. thumb: cursorData.string(forColumnIndex: 3) ?? "",
  238. userType: cursorData.string(forColumnIndex: 5) ?? "")
  239. if (user.firstName + " " + user.lastName).trimmingCharacters(in: .whitespaces) == "USR\(user.pin)" {
  240. continue
  241. }
  242. user.official = cursorData.string(forColumnIndex: 4) ?? ""
  243. if !self.contacts.contains(where: {$0.pin == user.pin}) {
  244. self.contacts.append(user)
  245. }
  246. }
  247. cursorData.close()
  248. }
  249. completion()
  250. })
  251. }
  252. }
  253. private func getGroupRecursive(fmdb: FMDatabase, id: String = "", parent: String = "") -> [Group] {
  254. var data: [Group] = []
  255. 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 "
  256. if id.isEmpty {
  257. query += "g.parent = '\(parent)'"
  258. } else {
  259. query += "g.group_id = '\(id)'"
  260. }
  261. query += "order by 10 desc"
  262. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: query) {
  263. while cursor.next() {
  264. let group = Group(
  265. id: cursor.string(forColumnIndex: 0) ?? "",
  266. name: cursor.string(forColumnIndex: 1) ?? "",
  267. profile: cursor.string(forColumnIndex: 2) ?? "",
  268. quote: cursor.string(forColumnIndex: 3) ?? "",
  269. by: cursor.string(forColumnIndex: 4) ?? "",
  270. date: cursor.string(forColumnIndex: 5) ?? "",
  271. parent: cursor.string(forColumnIndex: 6) ?? "",
  272. chatId: "",
  273. groupType: cursor.string(forColumnIndex: 7) ?? "",
  274. isOpen: cursor.string(forColumnIndex: 8) ?? "",
  275. official: cursor.string(forColumnIndex: 9) ?? "",
  276. isEducation: cursor.string(forColumnIndex: 10) ?? "",
  277. level: cursor.string(forColumnIndex: 11) ?? "")
  278. if group.chatId.isEmpty {
  279. 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")
  280. group.childs.append(lounge)
  281. }
  282. if let topicCursor = Database.shared.getRecords(fmdb: fmdb, query: "select chat_id, title, thumb from DISCUSSION_FORUM where group_id = '\(group.id)'") {
  283. while topicCursor.next() {
  284. let topic = Group(id: group.id,
  285. name: topicCursor.string(forColumnIndex: 1) ?? "",
  286. profile: topicCursor.string(forColumnIndex: 2) ?? "",
  287. quote: group.quote,
  288. by: group.by,
  289. date: group.date,
  290. parent: group.id,
  291. chatId: topicCursor.string(forColumnIndex: 0) ?? "",
  292. groupType: group.groupType,
  293. isOpen: group.isOpen,
  294. official: group.official,
  295. isEducation: group.isEducation,
  296. level: group.level != "-1" ? group.level : "2")
  297. group.childs.append(topic)
  298. }
  299. topicCursor.close()
  300. }
  301. if !group.id.isEmpty {
  302. // if group.official == "1" {
  303. // let idMe = UserDefaults.standard.string(forKey: "me") as String?
  304. // if let cursorUser = Database.shared.getRecords(fmdb: fmdb, query: "SELECT user_type FROM BUDDY where f_pin='\(idMe!)'"), cursorUser.next() {
  305. //// if cursorUser.string(forColumnIndex: 0) == "23" || cursorUser.string(forColumnIndex: 0) == "24" {
  306. //// group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
  307. //// }
  308. // group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
  309. // cursorUser.close()
  310. // }
  311. // } else if group.official != "1"{
  312. // group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
  313. // }
  314. group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
  315. // group.childs = group.childs.sorted(by: { $0.name < $1.name })
  316. // let dataLounge = group.childs.filter({$0.name == "Lounge".localized()})
  317. // group.childs = group.childs.filter({ $0.name != "Lounge".localized() })
  318. // group.childs.insert(contentsOf: dataLounge, at: 0)
  319. }
  320. data.append(group)
  321. }
  322. cursor.close()
  323. }
  324. return data
  325. }
  326. private func getOpenGroups(listGroups: [Group], completion: @escaping ([Group]) -> ()) {
  327. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getOpenGroups(p_account: "1,2,3,5,6,7", offset: "0", search: "")) {
  328. var dataGroups: [Group] = []
  329. if (response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "00") {
  330. let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
  331. if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [[String: Any?]] {
  332. for dataJson in json {
  333. let group = Group(
  334. id: dataJson[CoreMessage_TMessageKey.GROUP_ID] as? String ?? "",
  335. name: dataJson[CoreMessage_TMessageKey.GROUP_NAME] as? String ?? "",
  336. profile: dataJson[CoreMessage_TMessageKey.THUMB_ID] as? String ?? "",
  337. quote: dataJson[CoreMessage_TMessageKey.QUOTE] as? String ?? "",
  338. by: dataJson[CoreMessage_TMessageKey.BLOCK] as? String ?? "",
  339. date: "",
  340. parent: "",
  341. chatId: "",
  342. groupType: "NOTJOINED",
  343. isOpen: dataJson[CoreMessage_TMessageKey.IS_OPEN] as? String ?? "",
  344. official: "0",
  345. isEducation: "")
  346. dataGroups.append(group)
  347. }
  348. }
  349. } else {
  350. DispatchQueue.main.async {
  351. self.groups.removeAll()
  352. self.groups.append(contentsOf: listGroups)
  353. self.tableView.reloadData()
  354. }
  355. }
  356. completion(dataGroups)
  357. }
  358. }
  359. private func getGroups(id: String = "", parent: String = "", completion: @escaping ([Group]) -> ()) {
  360. DispatchQueue.global().async {
  361. Database.shared.database?.inTransaction({ fmdb, rollback in
  362. completion(self.getGroupRecursive(fmdb: fmdb, id: id, parent: parent))
  363. })
  364. }
  365. }
  366. private func pullBuddy() {
  367. if let me = UserDefaults.standard.string(forKey: "me") {
  368. DispatchQueue.global().async {
  369. let _ = Nexilis.write(message: CoreMessage_TMessageBank.getBatchBuddiesInfos(p_f_pin: me, last_update: 0))
  370. }
  371. }
  372. }
  373. private func joinOpenGroup(groupId: String, flagMember: String = "0", completion: @escaping (Bool) -> ()) {
  374. DispatchQueue.global().async {
  375. var result: Bool = false
  376. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  377. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getAddGroupMember(p_group_id: groupId, p_member_pin: idMe!, p_position: "0")), response.isOk() {
  378. result = true
  379. }
  380. completion(result)
  381. }
  382. }
  383. }
  384. // MARK: - Table view data source
  385. extension ContactChatViewController {
  386. override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  387. if noData {
  388. return
  389. }
  390. tableView.deselectRow(at: indexPath, animated: true)
  391. switch segment.selectedSegmentIndex {
  392. case 0:
  393. let data: Chat
  394. if isFilltering {
  395. data = fillteredData[indexPath.row] as! Chat
  396. } else {
  397. data = chats[indexPath.row]
  398. }
  399. if let chooser = isChooser {
  400. var exblock = User.getData(pin: data.pin)?.ex_block
  401. exblock = exblock == nil ? "0" : exblock!.isEmpty ? "0" : exblock!
  402. if exblock != "0" {
  403. if exblock == "1" {
  404. self.view.makeToast("You blocked this user".localized())
  405. } else {
  406. self.view.makeToast("You have been blocked by this user".localized())
  407. }
  408. return
  409. }
  410. if data.pin == "-999"{
  411. return
  412. }
  413. chooser(data.messageScope, data.pin)
  414. dismiss(animated: true, completion: nil)
  415. return
  416. }
  417. if data.messageScope == "3" {
  418. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  419. editorPersonalVC.hidesBottomBarWhenPushed = true
  420. editorPersonalVC.unique_l_pin = data.pin
  421. navigationController?.show(editorPersonalVC, sender: nil)
  422. } else {
  423. groupMap.removeAll()
  424. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  425. editorGroupVC.hidesBottomBarWhenPushed = true
  426. editorGroupVC.unique_l_pin = data.pin
  427. navigationController?.show(editorGroupVC, sender: nil)
  428. }
  429. case 1:
  430. let data: User
  431. if isFilltering {
  432. data = fillteredData[indexPath.row] as! User
  433. } else {
  434. data = contacts[indexPath.row]
  435. }
  436. if let chooser = isChooser {
  437. var exblock = User.getData(pin: data.pin)?.ex_block
  438. exblock = exblock == nil ? "0" : exblock!.isEmpty ? "0" : exblock!
  439. if exblock != "0" {
  440. if exblock == "1" {
  441. self.view.makeToast("You blocked this user".localized())
  442. } else {
  443. self.view.makeToast("You have been blocked by this user".localized())
  444. }
  445. return
  446. }
  447. chooser("3", data.pin)
  448. dismiss(animated: true, completion: nil)
  449. return
  450. }
  451. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  452. editorPersonalVC.hidesBottomBarWhenPushed = true
  453. editorPersonalVC.unique_l_pin = data.pin
  454. navigationController?.show(editorPersonalVC, sender: nil)
  455. case 2:
  456. expandCollapseGroup(tableView: tableView, indexPath: indexPath)
  457. default:
  458. let data = contacts[indexPath.row]
  459. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  460. editorPersonalVC.hidesBottomBarWhenPushed = true
  461. editorPersonalVC.unique_l_pin = data.pin
  462. navigationController?.show(editorPersonalVC, sender: nil)
  463. }
  464. }
  465. func expandCollapseGroup(tableView: UITableView, indexPath: IndexPath) {
  466. let group: Group
  467. if isFilltering {
  468. if indexPath.row == 0 {
  469. group = fillteredData[indexPath.section] as! Group
  470. } else {
  471. group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
  472. }
  473. } else {
  474. if indexPath.row == 0 {
  475. group = groups[indexPath.section]
  476. } else {
  477. group = groups[indexPath.section].childs[indexPath.row - 1]
  478. }
  479. }
  480. group.isSelected = !group.isSelected
  481. if !group.isSelected{
  482. var sects = 0
  483. var sect = indexPath.section
  484. var id = group.id
  485. if let _ = groupMap[id] {
  486. var loooop = true
  487. repeat {
  488. let c = sect + 1
  489. if isFilltering {
  490. if let o = self.fillteredData[c] as? Group {
  491. if o.parent == id {
  492. sects = sects + 1
  493. sect = c
  494. id = o.id
  495. (self.fillteredData[c] as! Group).isSelected = false
  496. self.groupMap.removeValue(forKey: (self.fillteredData[c] as! Group).id)
  497. }
  498. else {
  499. loooop = false
  500. }
  501. }
  502. }
  503. else {
  504. if c < self.groups.count && self.groups[c].parent == id {
  505. sects = sects + 1
  506. sect = c
  507. id = self.groups[c].id
  508. self.groups[c].isSelected = false
  509. self.groupMap.removeValue(forKey: self.groups[c].id)
  510. }
  511. else {
  512. loooop = false
  513. }
  514. }
  515. } while(loooop)
  516. }
  517. for i in stride(from: sects, to: 0, by: -1){
  518. if isFilltering {
  519. self.fillteredData.remove(at: indexPath.section + i)
  520. }
  521. else {
  522. self.groups.remove(at: indexPath.section + i)
  523. }
  524. }
  525. groupMap.removeValue(forKey: group.id)
  526. }
  527. if group.groupType == "NOTJOINED" {
  528. let alert = UIAlertController(title: "Do you want to join this group?".localized(), message: "Groups : \(group.name)\nMembers: \(group.by)".localized(), preferredStyle: .alert)
  529. alert.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
  530. alert.addAction(UIAlertAction(title: "Join".localized(), style: .default, handler: {(_) in
  531. self.joinOpenGroup(groupId: group.id, completion: { result in
  532. if result {
  533. DispatchQueue.main.async {
  534. self.groupMap.removeAll()
  535. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  536. editorGroupVC.hidesBottomBarWhenPushed = true
  537. editorGroupVC.unique_l_pin = group.id
  538. self.navigationController?.show(editorGroupVC, sender: nil)
  539. }
  540. }
  541. })
  542. }))
  543. self.present(alert, animated: true, completion: nil)
  544. return
  545. }
  546. if group.childs.count == 0 {
  547. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  548. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  549. 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() {
  550. let groupId = group.chatId.isEmpty ? group.id : group.chatId
  551. if let chooser = isChooser {
  552. chooser("4", groupId)
  553. dismiss(animated: true, completion: nil)
  554. return
  555. }
  556. self.groupMap.removeAll()
  557. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  558. editorGroupVC.hidesBottomBarWhenPushed = true
  559. editorGroupVC.unique_l_pin = groupId
  560. navigationController?.show(editorGroupVC, sender: nil)
  561. cursorMember.close()
  562. } else {
  563. self.view.makeToast("You are not a member of this group".localized(), duration: 0.5)
  564. }
  565. })
  566. } else {
  567. if indexPath.row == 0 {
  568. tableView.reloadData()
  569. } else {
  570. getGroups(id: group.id) { g in
  571. DispatchQueue.main.async {
  572. print("index path section: \(indexPath.section)")
  573. print("index path row: \(indexPath.row)")
  574. // print("index path item: \(indexPath.item)")
  575. if self.isFilltering {
  576. // self.fillteredData.remove(at: indexPath.section)
  577. if self.fillteredData[indexPath.section] is Group {
  578. self.groupMap[(self.fillteredData[indexPath.section] as! Group).id] = 1
  579. self.fillteredData.insert(contentsOf: g, at: indexPath.section + 1)
  580. }
  581. } else {
  582. // self.groups.remove(at: indexPath.section)
  583. self.groupMap[self.groups[indexPath.section].id] = 1
  584. self.groups.insert(contentsOf: g, at: indexPath.section + 1)
  585. }
  586. print("groupMap: \(self.groupMap)")
  587. tableView.reloadData()
  588. self.expandCollapseGroup(tableView: tableView, indexPath: IndexPath(row: 0, section: indexPath.section + 1))
  589. }
  590. }
  591. }
  592. }
  593. }
  594. }
  595. extension ContactChatViewController {
  596. override func numberOfSections(in tableView: UITableView) -> Int {
  597. if isFilltering {
  598. if segment.selectedSegmentIndex == 2 {
  599. return fillteredData.count
  600. }
  601. return 1
  602. } else {
  603. if segment.selectedSegmentIndex == 2 {
  604. return groups.count
  605. }
  606. return 1
  607. }
  608. }
  609. override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  610. var value = 0
  611. if isFilltering {
  612. if segment.selectedSegmentIndex == 2, let groups = fillteredData as? [Group] {
  613. let group = groups[section]
  614. if group.isSelected {
  615. if let _ = groupMap[group.id] {
  616. value = 1
  617. }
  618. else {
  619. value = group.childs.count + 1
  620. }
  621. } else {
  622. value = 1
  623. }
  624. } else {
  625. value = fillteredData.count
  626. }
  627. return value
  628. }
  629. switch segment.selectedSegmentIndex {
  630. case 0:
  631. value = chats.count
  632. case 1:
  633. value = contacts.count
  634. case 2:
  635. let group = groups[section]
  636. if group.isSelected {
  637. if let _ = groupMap[group.id] {
  638. value = 1
  639. }
  640. else {
  641. value = group.childs.count + 1
  642. }
  643. } else {
  644. value = 1
  645. }
  646. default:
  647. value = chats.count
  648. }
  649. if value == 0 {
  650. noData = true
  651. value = 1
  652. tableView.separatorStyle = .none
  653. } else {
  654. noData = false
  655. tableView.separatorStyle = .singleLine
  656. }
  657. return value
  658. }
  659. override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  660. var cell: UITableViewCell!
  661. switch segment.selectedSegmentIndex {
  662. case 0:
  663. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierChat", for: indexPath)
  664. let content = cell.contentView
  665. if content.subviews.count > 0 {
  666. content.subviews.forEach { $0.removeFromSuperview() }
  667. }
  668. if noData {
  669. let labelNochat = UILabel()
  670. labelNochat.text = "There are no conversations".localized()
  671. labelNochat.font = .systemFont(ofSize: 13)
  672. labelNochat.textColor = .black
  673. content.addSubview(labelNochat)
  674. labelNochat.anchor(centerX: content.centerXAnchor, centerY: content.centerYAnchor)
  675. cell.backgroundColor = .clear
  676. cell.selectionStyle = .none
  677. return cell
  678. }
  679. let data: Chat
  680. if isFilltering {
  681. data = fillteredData[indexPath.row] as! Chat
  682. } else {
  683. data = chats[indexPath.row]
  684. }
  685. let imageView = UIImageView()
  686. content.addSubview(imageView)
  687. imageView.translatesAutoresizingMaskIntoConstraints = false
  688. NSLayoutConstraint.activate([
  689. imageView.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 10.0),
  690. imageView.topAnchor.constraint(equalTo: content.topAnchor, constant: 10.0),
  691. imageView.bottomAnchor.constraint(equalTo: content.bottomAnchor, constant: -25.0),
  692. imageView.widthAnchor.constraint(equalToConstant: 40.0),
  693. imageView.heightAnchor.constraint(equalToConstant: 40.0)
  694. ])
  695. if data.profile.isEmpty && data.pin != "-999" {
  696. if data.messageScope == "3" {
  697. imageView.image = UIImage(named: "Profile---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  698. } else {
  699. imageView.image = UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  700. }
  701. } else {
  702. if Utils.getIconDock() != nil {
  703. 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
  704. if dataImage != nil {
  705. getImage(name: data.profile, placeholderImage: UIImage(data: dataImage!), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
  706. imageView.image = image
  707. })
  708. }
  709. } else {
  710. getImage(name: data.profile, placeholderImage: UIImage(named: data.pin == "-999" ? "pb_button" : "Conversation---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
  711. imageView.image = image
  712. })
  713. }
  714. }
  715. let titleView = UILabel()
  716. content.addSubview(titleView)
  717. titleView.translatesAutoresizingMaskIntoConstraints = false
  718. NSLayoutConstraint.activate([
  719. titleView.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10.0),
  720. titleView.topAnchor.constraint(equalTo: content.topAnchor, constant: 10.0),
  721. titleView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
  722. ])
  723. titleView.text = data.name
  724. titleView.font = UIFont.systemFont(ofSize: 14, weight: .medium)
  725. let messageView = UILabel()
  726. content.addSubview(messageView)
  727. messageView.translatesAutoresizingMaskIntoConstraints = false
  728. NSLayoutConstraint.activate([
  729. messageView.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10.0),
  730. messageView.topAnchor.constraint(equalTo: titleView.bottomAnchor, constant: 5.0),
  731. messageView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
  732. ])
  733. messageView.textColor = .gray
  734. let text = Utils.previewMessageText(chat: data)
  735. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  736. if let attributeText = text as? NSAttributedString {
  737. if data.fpin == idMe {
  738. let stringMessage = NSMutableAttributedString(string: "")
  739. let imageStatus = NSTextAttachment()
  740. let status = getRealStatus(messageId: data.messageId)
  741. if (status == "1" || status == "2" ) {
  742. imageStatus.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.lightGray)
  743. } else if (status == "3") {
  744. imageStatus.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.lightGray)
  745. } else if (status == "8") {
  746. imageStatus.image = UIImage(named: "message_status_ack", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal)
  747. } else {
  748. imageStatus.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.systemBlue)
  749. }
  750. imageStatus.bounds = CGRect(x: 0, y: 0, width: 15, height: 15)
  751. let imageStatusString = NSAttributedString(attachment: imageStatus)
  752. stringMessage.append(imageStatusString)
  753. stringMessage.append(NSAttributedString(string: " "))
  754. stringMessage.append(attributeText)
  755. messageView.attributedText = stringMessage
  756. } else {
  757. messageView.attributedText = attributeText
  758. }
  759. } else if let stringText = text as? String {
  760. if data.fpin == idMe {
  761. let stringMessage = NSMutableAttributedString(string: "")
  762. let imageStatus = NSTextAttachment()
  763. let status = getRealStatus(messageId: data.messageId)
  764. if (status == "1" || status == "2" ) {
  765. imageStatus.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.lightGray)
  766. } else if (status == "3") {
  767. imageStatus.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.lightGray)
  768. } else if (status == "8") {
  769. imageStatus.image = UIImage(named: "message_status_ack", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal)
  770. } else {
  771. imageStatus.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.systemBlue)
  772. }
  773. imageStatus.bounds = CGRect(x: 0, y: 0, width: 15, height: 15)
  774. let imageStatusString = NSAttributedString(attachment: imageStatus)
  775. stringMessage.append(imageStatusString)
  776. stringMessage.append(NSAttributedString(string: " "))
  777. stringMessage.append(NSAttributedString(string: stringText))
  778. messageView.attributedText = stringMessage
  779. } else {
  780. messageView.text = stringText
  781. }
  782. }
  783. messageView.numberOfLines = 2
  784. if data.counter != "0" {
  785. let viewCounter = UIView()
  786. content.addSubview(viewCounter)
  787. viewCounter.translatesAutoresizingMaskIntoConstraints = false
  788. NSLayoutConstraint.activate([
  789. viewCounter.centerYAnchor.constraint(equalTo: content.centerYAnchor),
  790. viewCounter.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -20),
  791. viewCounter.widthAnchor.constraint(greaterThanOrEqualToConstant: 20),
  792. viewCounter.heightAnchor.constraint(equalToConstant: 20)
  793. ])
  794. viewCounter.backgroundColor = .systemRed
  795. viewCounter.layer.cornerRadius = 10
  796. viewCounter.clipsToBounds = true
  797. viewCounter.layer.borderWidth = 0.5
  798. viewCounter.layer.borderColor = UIColor.secondaryColor.cgColor
  799. let labelCounter = UILabel()
  800. viewCounter.addSubview(labelCounter)
  801. labelCounter.translatesAutoresizingMaskIntoConstraints = false
  802. NSLayoutConstraint.activate([
  803. labelCounter.centerYAnchor.constraint(equalTo: viewCounter.centerYAnchor),
  804. labelCounter.leadingAnchor.constraint(equalTo: viewCounter.leadingAnchor, constant: 2),
  805. labelCounter.trailingAnchor.constraint(equalTo: viewCounter.trailingAnchor, constant: -2),
  806. ])
  807. labelCounter.font = UIFont.systemFont(ofSize: 11)
  808. if Int(data.counter)! > 99 {
  809. labelCounter.text = "99+"
  810. } else {
  811. labelCounter.text = data.counter
  812. }
  813. labelCounter.textColor = .secondaryColor
  814. labelCounter.textAlignment = .center
  815. }
  816. case 1:
  817. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierContact", for: indexPath)
  818. var content = cell.defaultContentConfiguration()
  819. let data: User
  820. if isFilltering {
  821. data = fillteredData[indexPath.row] as! User
  822. } else {
  823. if indexPath.row > contacts.count - 1 {
  824. return cell
  825. }
  826. data = contacts[indexPath.row]
  827. }
  828. content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
  829. getImage(name: data.thumb, placeholderImage: UIImage(named: "Profile---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
  830. content.image = image
  831. })
  832. if User.isOfficial(official_account: data.official ?? "") || User.isOfficialRegular(official_account: data.official ?? "") {
  833. content.attributedText = self.set(image: UIImage(named: "ic_official_flag", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.officialColor)
  834. } else if User.isVerified(official_account: data.official ?? "") {
  835. content.attributedText = self.set(image: UIImage(named: "ic_verified", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.verifiedColor)
  836. }
  837. else if User.isInternal(userType: data.userType ?? "") {
  838. content.attributedText = self.set(image: UIImage(named: "ic_internal", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.internalColor)
  839. } else if User.isCallCenter(userType: data.userType ?? "") {
  840. let dataCategory = CategoryCC.getDataFromServiceId(service_id: data.ex_offmp!)
  841. if dataCategory != nil {
  842. content.attributedText = self.set(image: UIImage(named: "pb_call_center", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, with: " \(data.fullName) (\(dataCategory!.service_name))", size: 15, y: -4, colorText: UIColor.ccColor)
  843. } else {
  844. content.attributedText = self.set(image: UIImage(named: "pb_call_center", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, with: " \(data.fullName)", size: 15, y: -4, colorText: UIColor.ccColor)
  845. }
  846. } else {
  847. content.text = data.fullName
  848. }
  849. content.textProperties.font = UIFont.systemFont(ofSize: 14)
  850. cell.contentConfiguration = content
  851. case 2:
  852. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierGroup", for: indexPath)
  853. var content = cell.defaultContentConfiguration()
  854. content.textProperties.font = UIFont.systemFont(ofSize: 14)
  855. let group: Group
  856. if isFilltering {
  857. if indexPath.row == 0 {
  858. group = fillteredData[indexPath.section] as! Group
  859. } else {
  860. group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
  861. }
  862. } else {
  863. if indexPath.row == 0 {
  864. group = groups[indexPath.section]
  865. } else {
  866. group = groups[indexPath.section].childs[indexPath.row - 1]
  867. }
  868. }
  869. if group.official == "1" && group.parent == "" {
  870. content.attributedText = self.set(image: UIImage(named: "ic_official_flag", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, with: " \(group.name)", size: 15, y: -4)
  871. }
  872. else if group.isOpen == "1" && group.parent == "" {
  873. if self.traitCollection.userInterfaceStyle == .dark {
  874. content.attributedText = self.set(image: UIImage(systemName: "globe")!.withTintColor(.white), with: " \(group.name)", size: 15, y: -4)
  875. } else {
  876. content.attributedText = self.set(image: UIImage(systemName: "globe")!, with: " \(group.name)", size: 15, y: -4)
  877. }
  878. } else if group.parent == "" {
  879. if self.traitCollection.userInterfaceStyle == .dark {
  880. content.attributedText = self.set(image: UIImage(systemName: "lock.fill")!.withTintColor(.white), with: " \(group.name)", size: 15, y: -4)
  881. } else {
  882. content.attributedText = self.set(image: UIImage(systemName: "lock.fill")!, with: " \(group.name)", size: 15, y: -4)
  883. }
  884. } else {
  885. content.text = group.name
  886. }
  887. if group.childs.count > 0 {
  888. let iconName = (group.isSelected) ? "chevron.up.circle" : "chevron.down.circle"
  889. let imageView = UIImageView(image: UIImage(systemName: iconName))
  890. imageView.tintColor = .black
  891. cell.accessoryView = imageView
  892. }
  893. else {
  894. cell.accessoryView = nil
  895. cell.accessoryType = .none
  896. }
  897. content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
  898. getImage(name: group.profile, placeholderImage: UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath) { result, isDownloaded, image in
  899. content.image = image
  900. }
  901. cell.contentConfiguration = content
  902. if !group.level.isEmpty {
  903. if group.level != "-1" && Int(group.level)! < 7 {
  904. cell.contentView.layoutMargins = .init(top: 0.0, left: CGFloat(25 * Int(group.level)!), bottom: 0.0, right: 0)
  905. } else if Int(group.level)! > 6 {
  906. cell.contentView.layoutMargins = .init(top: 0.0, left: CGFloat(25 * (Int(group.level)! - 6)), bottom: 0.0, right: 0)
  907. }
  908. }
  909. default:
  910. cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierContact", for: indexPath)
  911. var content = cell.defaultContentConfiguration()
  912. content.text = ""
  913. cell.contentConfiguration = content
  914. }
  915. cell.backgroundColor = .clear
  916. cell.separatorInset = UIEdgeInsets(top: 0, left: 60.0, bottom: 0, right: 0)
  917. return cell
  918. }
  919. override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  920. return 75.0
  921. }
  922. private func getRealStatus(messageId: String) -> String {
  923. var status = "1"
  924. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  925. if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status, f_pin FROM MESSAGE_STATUS WHERE message_id='\(messageId)'") {
  926. var listStatus: [Int] = []
  927. while cursorStatus.next() {
  928. listStatus.append(Int(cursorStatus.string(forColumnIndex: 0)!)!)
  929. }
  930. cursorStatus.close()
  931. status = "\(listStatus.min() ?? 2)"
  932. }
  933. })
  934. return status
  935. }
  936. }
  937. extension ContactChatViewController: UISearchControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating {
  938. func updateSearchResults(for searchController: UISearchController) {
  939. filterContentForSearchText(searchController.searchBar.text!.trimmingCharacters(in: .whitespacesAndNewlines))
  940. }
  941. func set(image: UIImage, with text: String, size: CGFloat, y: CGFloat, colorText: UIColor = UIColor.black) -> NSAttributedString {
  942. let attachment = NSTextAttachment()
  943. attachment.image = image
  944. attachment.bounds = CGRect(x: 0, y: y, width: size, height: size)
  945. let attachmentStr = NSAttributedString(attachment: attachment)
  946. let mutableAttributedString = NSMutableAttributedString()
  947. mutableAttributedString.append(attachmentStr)
  948. let attributedStringColor = [NSAttributedString.Key.foregroundColor : colorText]
  949. let textString = NSAttributedString(string: text, attributes: attributedStringColor)
  950. mutableAttributedString.append(textString)
  951. return mutableAttributedString
  952. }
  953. func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
  954. searchBar.showsCancelButton = true
  955. let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
  956. cBtn.setTitle("Cancel".localized(), for: .normal)
  957. }
  958. func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
  959. searchBar.showsCancelButton = false
  960. }
  961. }