EditorStarMessages.swift 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  1. //
  2. // EditorStarMessages.swift
  3. // Qmera
  4. //
  5. // Created by Akhmad Al Qindi Irsyam on 22/09/21.
  6. //
  7. import UIKit
  8. import AVKit
  9. import AVFoundation
  10. import QuickLook
  11. import Photos
  12. public class EditorStarMessages: UIViewController, UITableViewDataSource, UITableViewDelegate, UIContextMenuInteractionDelegate, QLPreviewControllerDataSource {
  13. @IBOutlet var tableChatView: UITableView!
  14. var dataMessages: [[String: Any?]] = []
  15. var dataDates: [String] = []
  16. var previewItem = NSURL()
  17. var fromNotification = false
  18. public override func viewDidLoad() {
  19. super.viewDidLoad()
  20. if fromNotification {
  21. let imageButton = UIImageView(frame: CGRect(x: -16, y: 0, width: 20, height: 44))
  22. imageButton.image = UIImage(systemName: "chevron.backward", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular, scale: .default))?.withTintColor(.white)
  23. imageButton.contentMode = .left
  24. let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapExit))
  25. imageButton.isUserInteractionEnabled = true
  26. imageButton.addGestureRecognizer(tapGestureRecognizer)
  27. let leftItem = UIBarButtonItem(customView: imageButton)
  28. self.navigationItem.leftBarButtonItem = leftItem
  29. }
  30. navigationController?.navigationBar.isTranslucent = false
  31. navigationController?.navigationBar.barTintColor = UIColor.mainColor
  32. navigationController?.navigationBar.tintColor = .white
  33. navigationController?.navigationBar.topItem?.title = ""
  34. self.title = "Favorite Messages".localized()
  35. let menu = UIMenu(title: "", children: [
  36. UIAction(title: "Unfavorite all messages".localized(), handler: {(_) in
  37. DispatchQueue.global().async {
  38. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  39. _ = Database.shared.updateAllRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  40. "is_stared" : 0
  41. ])
  42. })
  43. }
  44. self.dataMessages.removeAll()
  45. self.tableChatView.reloadData()
  46. }),
  47. ])
  48. getData()
  49. let moreIcon = UIBarButtonItem(image: UIImage(systemName: "ellipsis"), menu: menu)
  50. navigationItem.rightBarButtonItem = moreIcon
  51. navigationItem.rightBarButtonItem?.tintColor = UIColor.secondaryColor
  52. tableChatView.delegate = self
  53. tableChatView.dataSource = self
  54. tableChatView.reloadData()
  55. let center: NotificationCenter = NotificationCenter.default
  56. center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
  57. }
  58. @objc func didTapExit() {
  59. self.dismiss(animated: true, completion: nil)
  60. }
  61. @objc func onStatusChat(notification: NSNotification) {
  62. DispatchQueue.main.async {
  63. let data:[AnyHashable : Any] = notification.userInfo!
  64. if let dataMessage = data["message"] as? TMessage {
  65. let chatData = dataMessage.mBodies
  66. if (chatData.keys.contains(CoreMessage_TMessageKey.MESSAGE_ID) && !(chatData[CoreMessage_TMessageKey.MESSAGE_ID]!).contains("-2,")) {
  67. let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as? String == chatData[CoreMessage_TMessageKey.MESSAGE_ID]! })
  68. if (idx != nil) {
  69. if (chatData[CoreMessage_TMessageKey.DELETE_MESSAGE_FLAG] == "1") {
  70. let section = self.dataDates.firstIndex(of: self.dataMessages[idx!]["chat_date"] as! String)
  71. let row = self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[idx!]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[idx!]["message_id"] as? String })
  72. self.dataMessages.remove(at: idx!)
  73. if row != nil && section != nil {
  74. let indexPath = IndexPath(row: row!, section: section!)
  75. self.tableChatView.deleteRows(at: [indexPath], with: .fade)
  76. if self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[indexPath.row]["chat_date"] as! String }).count == 0 {
  77. self.dataDates.remove(at: indexPath.section)
  78. self.tableChatView.deleteSections(IndexSet(integer: indexPath.section), with: .fade)
  79. }
  80. }
  81. }
  82. }
  83. }
  84. else if (chatData.keys.contains("message_id")) {
  85. let idx = self.dataMessages.firstIndex(where: { "'\(String(describing: $0["message_id"] as? String))'" == chatData["message_id"]! })
  86. if (idx != nil) {
  87. if (chatData[CoreMessage_TMessageKey.DELETE_MESSAGE_FLAG] == "1") {
  88. let section = self.dataDates.firstIndex(of: self.dataMessages[idx!]["chat_date"] as! String)
  89. let row = self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[idx!]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == self.dataMessages[idx!]["message_id"] as? String })
  90. self.dataMessages.remove(at: idx!)
  91. if row != nil && section != nil {
  92. let indexPath = IndexPath(row: row!, section: section!)
  93. self.tableChatView.deleteRows(at: [indexPath], with: .fade)
  94. if self.dataMessages.filter({ $0["chat_date"] as! String == self.dataMessages[indexPath.row]["chat_date"] as! String }).count == 0 {
  95. self.dataDates.remove(at: indexPath.section)
  96. self.tableChatView.deleteSections(IndexSet(integer: indexPath.section), with: .fade)
  97. }
  98. }
  99. }
  100. }
  101. }
  102. }
  103. }
  104. }
  105. public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
  106. let containerView = UIView()
  107. containerView.backgroundColor = .clear
  108. let dateView = UIView()
  109. containerView.addSubview(dateView)
  110. dateView.translatesAutoresizingMaskIntoConstraints = false
  111. var topAnchor = dateView.topAnchor.constraint(equalTo: containerView.topAnchor)
  112. if section == 0 {
  113. topAnchor = dateView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 10.0)
  114. }
  115. NSLayoutConstraint.activate([
  116. topAnchor,
  117. dateView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
  118. dateView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
  119. dateView.heightAnchor.constraint(equalToConstant: 30),
  120. dateView.widthAnchor.constraint(greaterThanOrEqualToConstant: 60)
  121. ])
  122. dateView.backgroundColor = .orangeColor
  123. dateView.layer.cornerRadius = 15.0
  124. dateView.clipsToBounds = true
  125. let labelDate = UILabel()
  126. dateView.addSubview(labelDate)
  127. labelDate.translatesAutoresizingMaskIntoConstraints = false
  128. NSLayoutConstraint.activate([
  129. labelDate.centerYAnchor.constraint(equalTo: dateView.centerYAnchor),
  130. labelDate.centerXAnchor.constraint(equalTo: dateView.centerXAnchor),
  131. labelDate.leadingAnchor.constraint(equalTo: dateView.leadingAnchor, constant: 10),
  132. labelDate.trailingAnchor.constraint(equalTo: dateView.trailingAnchor, constant: -10),
  133. ])
  134. labelDate.textAlignment = .center
  135. labelDate.textColor = .secondaryColor
  136. labelDate.font = UIFont.systemFont(ofSize: 12, weight: .medium)
  137. labelDate.text = dataDates[section]
  138. return containerView
  139. }
  140. public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
  141. if section == 0 {
  142. return 40
  143. }
  144. return 30
  145. }
  146. public func numberOfSections(in tableView: UITableView) -> Int {
  147. dataDates.count
  148. }
  149. public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  150. let count = dataMessages.filter({ $0["chat_date"] as! String == dataDates[section] }).count
  151. return count
  152. }
  153. public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  154. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  155. let dataMessages = dataMessages.filter({$0["chat_date"] as! String == dataDates[indexPath.section]})
  156. let cellMessage = UITableViewCell()
  157. cellMessage.backgroundColor = .clear
  158. cellMessage.selectionStyle = .none
  159. let profileMessage = UIImageView()
  160. profileMessage.frame.size = CGSize(width: 35, height: 35)
  161. cellMessage.contentView.addSubview(profileMessage)
  162. profileMessage.translatesAutoresizingMaskIntoConstraints = false
  163. let containerMessage = UIView()
  164. let interaction = UIContextMenuInteraction(delegate: self)
  165. containerMessage.addInteraction(interaction)
  166. containerMessage.isUserInteractionEnabled = true
  167. cellMessage.contentView.addSubview(containerMessage)
  168. containerMessage.translatesAutoresizingMaskIntoConstraints = false
  169. let timeMessage = UILabel()
  170. cellMessage.contentView.addSubview(timeMessage)
  171. timeMessage.translatesAutoresizingMaskIntoConstraints = false
  172. timeMessage.bottomAnchor.constraint(equalTo: cellMessage.contentView.bottomAnchor, constant: -5).isActive = true
  173. let messageText = UILabel()
  174. containerMessage.addSubview(messageText)
  175. messageText.translatesAutoresizingMaskIntoConstraints = false
  176. let topMarginText = messageText.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 32)
  177. let dataProfile = getDataProfile(f_pin: dataMessages[indexPath.row]["f_pin"] as! String)
  178. let statusMessage = UIImageView()
  179. if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
  180. profileMessage.topAnchor.constraint(equalTo: cellMessage.contentView.topAnchor, constant: 5).isActive = true
  181. profileMessage.trailingAnchor.constraint(equalTo: cellMessage.contentView.trailingAnchor, constant: -15).isActive = true
  182. profileMessage.heightAnchor.constraint(equalToConstant: 37).isActive = true
  183. profileMessage.widthAnchor.constraint(equalToConstant: 35).isActive = true
  184. profileMessage.circle()
  185. profileMessage.clipsToBounds = true
  186. profileMessage.backgroundColor = .lightGray
  187. profileMessage.image = UIImage(systemName: "person")
  188. profileMessage.tintColor = .white
  189. profileMessage.contentMode = .scaleAspectFit
  190. let pictureImage = dataProfile["image_id"]
  191. if (pictureImage != "" && pictureImage != nil) {
  192. profileMessage.setImage(name: pictureImage!)
  193. profileMessage.contentMode = .scaleAspectFill
  194. }
  195. containerMessage.topAnchor.constraint(equalTo: cellMessage.contentView.topAnchor, constant: 5).isActive = true
  196. containerMessage.leadingAnchor.constraint(greaterThanOrEqualTo: cellMessage.contentView.leadingAnchor, constant: 80).isActive = true
  197. containerMessage.bottomAnchor.constraint(equalTo: cellMessage.contentView.bottomAnchor, constant: -5).isActive = true
  198. containerMessage.trailingAnchor.constraint(equalTo: profileMessage.leadingAnchor, constant: -5).isActive = true
  199. containerMessage.widthAnchor.constraint(greaterThanOrEqualToConstant: 46).isActive = true
  200. if (dataMessages[indexPath.row]["attachment_flag"] as? String == "11" && dataMessages[indexPath.row]["reff_id"]as? String == "") {
  201. containerMessage.backgroundColor = .clear
  202. } else {
  203. containerMessage.backgroundColor = .mainColor
  204. }
  205. containerMessage.layer.cornerRadius = 10.0
  206. containerMessage.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMinXMinYCorner]
  207. containerMessage.clipsToBounds = true
  208. timeMessage.trailingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: -8).isActive = true
  209. cellMessage.contentView.addSubview(statusMessage)
  210. statusMessage.translatesAutoresizingMaskIntoConstraints = false
  211. statusMessage.bottomAnchor.constraint(equalTo: timeMessage.topAnchor).isActive = true
  212. statusMessage.trailingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: -8).isActive = true
  213. statusMessage.widthAnchor.constraint(equalToConstant: 15).isActive = true
  214. statusMessage.heightAnchor.constraint(equalToConstant: 15).isActive = true
  215. if (dataMessages[indexPath.row]["status"]! as! String == "1" || dataMessages[indexPath.row]["status"]! as! String == "2" ) {
  216. statusMessage.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!.withTintColor(UIColor.lightGray)
  217. } else if (dataMessages[indexPath.row]["status"]! as! String == "3") {
  218. statusMessage.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!.withTintColor(UIColor.lightGray)
  219. } else {
  220. statusMessage.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: DigiX.self), with: nil)!.withTintColor(UIColor.systemBlue)
  221. }
  222. let nameSender = UILabel()
  223. containerMessage.addSubview(nameSender)
  224. nameSender.translatesAutoresizingMaskIntoConstraints = false
  225. nameSender.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 15).isActive = true
  226. nameSender.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
  227. nameSender.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
  228. nameSender.font = UIFont.systemFont(ofSize: 12).bold
  229. nameSender.text = dataProfile["name"]
  230. nameSender.textAlignment = .right
  231. if (dataMessages[indexPath.row]["attachment_flag"] as? String == "11" && dataMessages[indexPath.row]["reff_id"]as? String == "") {
  232. containerMessage.backgroundColor = .clear
  233. nameSender.textColor = .mainColor
  234. } else {
  235. containerMessage.backgroundColor = .mainColor
  236. nameSender.textColor = .white
  237. }
  238. } else {
  239. profileMessage.topAnchor.constraint(equalTo: cellMessage.contentView.topAnchor, constant: 5).isActive = true
  240. profileMessage.leadingAnchor.constraint(equalTo: cellMessage.contentView.leadingAnchor, constant: 15).isActive = true
  241. profileMessage.heightAnchor.constraint(equalToConstant: 37).isActive = true
  242. profileMessage.widthAnchor.constraint(equalToConstant: 35).isActive = true
  243. profileMessage.circle()
  244. profileMessage.clipsToBounds = true
  245. profileMessage.backgroundColor = .lightGray
  246. profileMessage.image = UIImage(systemName: "person")
  247. profileMessage.tintColor = .white
  248. profileMessage.contentMode = .scaleAspectFit
  249. let pictureImage = dataProfile["image_id"]
  250. if dataMessages[indexPath.row]["f_pin"] as! String == "-999" {
  251. if Utils.getIconDock() != nil {
  252. 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
  253. if dataImage != nil {
  254. profileMessage.image = UIImage(data: dataImage!)
  255. }
  256. } else {
  257. profileMessage.image = UIImage(named: "pb_button", in: Bundle.resourceBundle(for: DigiX.self), with: nil)
  258. }
  259. profileMessage.contentMode = .scaleAspectFit
  260. }
  261. if (pictureImage != "" && pictureImage != nil) {
  262. profileMessage.setImage(name: pictureImage!)
  263. profileMessage.contentMode = .scaleAspectFill
  264. }
  265. containerMessage.topAnchor.constraint(equalTo: cellMessage.contentView.topAnchor, constant: 5).isActive = true
  266. containerMessage.leadingAnchor.constraint(equalTo: profileMessage.trailingAnchor, constant: 5).isActive = true
  267. containerMessage.bottomAnchor.constraint(equalTo: cellMessage.contentView.bottomAnchor, constant: -5).isActive = true
  268. containerMessage.trailingAnchor.constraint(lessThanOrEqualTo: cellMessage.contentView.trailingAnchor, constant: -80).isActive = true
  269. containerMessage.widthAnchor.constraint(greaterThanOrEqualToConstant: 46).isActive = true
  270. if (dataMessages[indexPath.row]["attachment_flag"] as? String == "11" && dataMessages[indexPath.row]["reff_id"]as? String == "") {
  271. containerMessage.backgroundColor = .clear
  272. } else {
  273. containerMessage.backgroundColor = .grayColor
  274. }
  275. containerMessage.layer.cornerRadius = 10.0
  276. containerMessage.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
  277. containerMessage.clipsToBounds = true
  278. timeMessage.leadingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: 8).isActive = true
  279. let nameSender = UILabel()
  280. containerMessage.addSubview(nameSender)
  281. nameSender.translatesAutoresizingMaskIntoConstraints = false
  282. nameSender.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 15).isActive = true
  283. nameSender.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
  284. nameSender.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
  285. nameSender.font = UIFont.systemFont(ofSize: 12).bold
  286. nameSender.text = dataProfile["name"]
  287. nameSender.textAlignment = .left
  288. nameSender.textColor = .mainColor
  289. }
  290. if (dataMessages[indexPath.row]["is_stared"] as? String == "1") {
  291. let imageStared = UIImageView()
  292. cellMessage.contentView.addSubview(imageStared)
  293. imageStared.translatesAutoresizingMaskIntoConstraints = false
  294. if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
  295. imageStared.bottomAnchor.constraint(equalTo: statusMessage.topAnchor).isActive = true
  296. imageStared.trailingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: -8).isActive = true
  297. } else {
  298. imageStared.bottomAnchor.constraint(equalTo: timeMessage.topAnchor).isActive = true
  299. imageStared.leadingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: 8).isActive = true
  300. }
  301. imageStared.widthAnchor.constraint(equalToConstant: 15).isActive = true
  302. imageStared.heightAnchor.constraint(equalToConstant: 15).isActive = true
  303. imageStared.image = UIImage(systemName: "star.fill")
  304. imageStared.backgroundColor = .clear
  305. imageStared.tintColor = .systemYellow
  306. }
  307. messageText.numberOfLines = 0
  308. messageText.lineBreakMode = .byWordWrapping
  309. containerMessage.addSubview(messageText)
  310. topMarginText.isActive = true
  311. if dataMessages[indexPath.row]["attachment_flag"] as! String == "27" || dataMessages[indexPath.row]["attachment_flag"] as! String == "26" {
  312. messageText.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 85).isActive = true
  313. let imageLS = UIImageView()
  314. containerMessage.addSubview(imageLS)
  315. imageLS.translatesAutoresizingMaskIntoConstraints = false
  316. NSLayoutConstraint.activate([
  317. imageLS.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15.0),
  318. imageLS.trailingAnchor.constraint(equalTo: messageText.leadingAnchor, constant: -10.0),
  319. imageLS.centerYAnchor.constraint(equalTo: containerMessage.centerYAnchor),
  320. imageLS.heightAnchor.constraint(equalToConstant: 60.0)
  321. ])
  322. if dataMessages[indexPath.row]["attachment_flag"] as! String == "26" {
  323. imageLS.image = UIImage(named: "pb_seminar_wpr", in: Bundle.resourceBundle(for: DigiX.self), with: nil)
  324. } else if dataMessages[indexPath.row]["attachment_flag"] as! String == "27" {
  325. imageLS.image = UIImage(named: "pb_live_tv", in: Bundle.resourceBundle(for: DigiX.self), with: nil)
  326. }
  327. } else {
  328. messageText.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
  329. }
  330. messageText.bottomAnchor.constraint(equalTo: containerMessage.bottomAnchor, constant: -15).isActive = true
  331. messageText.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
  332. var textChat = (dataMessages[indexPath.row]["message_text"])! as? String
  333. if (dataMessages[indexPath.row]["lock"] != nil && (dataMessages[indexPath.row]["lock"])! as? String == "1") {
  334. if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
  335. textChat = "🚫 _"+"You were deleted this message".localized()+"_"
  336. } else {
  337. textChat = "🚫 _"+"This message was deleted".localized()+"_"
  338. }
  339. }
  340. if let attachmentFlag = dataMessages[indexPath.row]["attachment_flag"], let attachmentFlag = attachmentFlag as? String {
  341. if attachmentFlag == "27" || attachmentFlag == "26", let data = textChat { // live streaming
  342. if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [String: Any] {
  343. Database().database?.inTransaction({ fmdb, rollback in
  344. let title = json["title"] as! String
  345. let description = json["description"] as! String
  346. let start = json["time"] as! Int64
  347. let by = json["by"] as! String
  348. var type = "*Live Streaming*"
  349. if attachmentFlag == "26" {
  350. type = "*Seminar*"
  351. }
  352. if let c = Database().getRecords(fmdb: fmdb, query: "select first_name || ' ' || last_name from BUDDY where f_pin = '\(by)'"), c.next() {
  353. let name = c.string(forColumnIndex: 0)!
  354. messageText.attributedText = "\(type) \nTitle: \(title) \nDescription: \(description) \nStart: \(Date(milliseconds: start).format(dateFormat: "dd/MM/yyyy HH:mm")) \nBroadcaster: \(name)".richText()
  355. c.close()
  356. } else {
  357. messageText.attributedText = ("\(type) \nTitle: \(title) \nDescription: \(description) \nStart: \(Date(milliseconds: start).format(dateFormat: "dd/MM/yyyy HH:mm")) \nBroadcaster: " + "Unknown".localized()).richText()
  358. }
  359. })
  360. }
  361. } else if attachmentFlag == "11" {
  362. messageText.text = ""
  363. topMarginText.constant = topMarginText.constant + 100
  364. let imageSticker = UIImageView()
  365. containerMessage.addSubview(imageSticker)
  366. imageSticker.translatesAutoresizingMaskIntoConstraints = false
  367. imageSticker.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 27.0).isActive = true
  368. imageSticker.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor).isActive = true
  369. imageSticker.bottomAnchor.constraint(equalTo: messageText.topAnchor, constant: -5).isActive = true
  370. imageSticker.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor).isActive = true
  371. imageSticker.widthAnchor.constraint(equalToConstant: 80).isActive = true
  372. imageSticker.image = UIImage(named: (textChat?.components(separatedBy: "/")[1])!, in: Bundle.resourceBundle(for: DigiX.self), with: nil) //resourcesMediaBundle
  373. imageSticker.contentMode = .scaleAspectFit
  374. }
  375. else {
  376. messageText.attributedText = textChat!.richText()
  377. }
  378. } else {
  379. messageText.attributedText = textChat!.richText()
  380. }
  381. messageText.font = UIFont.systemFont(ofSize: 12)
  382. if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
  383. messageText.textColor = .white
  384. } else {
  385. messageText.textColor = .black
  386. }
  387. let stringDate = (dataMessages[indexPath.row]["server_date"] as! String)
  388. let date = Date(milliseconds: Int64(stringDate)!)
  389. let formatter = DateFormatter()
  390. formatter.dateFormat = "HH:mm"
  391. formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
  392. timeMessage.text = formatter.string(from: date as Date)
  393. timeMessage.font = UIFont.systemFont(ofSize: 10, weight: .medium)
  394. timeMessage.textColor = .lightGray
  395. let thumbChat = dataMessages[indexPath.row]["thumb_id"] as! String
  396. let imageChat = dataMessages[indexPath.row]["image_id"] as! String
  397. let videoChat = dataMessages[indexPath.row]["video_id"] as! String
  398. let fileChat = dataMessages[indexPath.row]["file_id"] as! String
  399. let imageThumb = UIImageView()
  400. let containerViewFile = UIView()
  401. if (thumbChat != "") {
  402. topMarginText.constant = topMarginText.constant + 205
  403. containerMessage.addSubview(imageThumb)
  404. imageThumb.translatesAutoresizingMaskIntoConstraints = false
  405. imageThumb.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 32).isActive = true
  406. imageThumb.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
  407. imageThumb.bottomAnchor.constraint(equalTo: messageText.topAnchor, constant: -5).isActive = true
  408. imageThumb.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
  409. imageThumb.widthAnchor.constraint(equalToConstant: self.view.frame.size.width * 0.6).isActive = true
  410. imageThumb.layer.cornerRadius = 5.0
  411. imageThumb.clipsToBounds = true
  412. imageThumb.contentMode = .scaleAspectFill
  413. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  414. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  415. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  416. if let dirPath = paths.first {
  417. let thumbURL = URL(fileURLWithPath: dirPath).appendingPathComponent(thumbChat)
  418. let image = UIImage(contentsOfFile: thumbURL.path)
  419. imageThumb.image = image
  420. let videoURL = URL(fileURLWithPath: dirPath).appendingPathComponent(videoChat)
  421. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(imageChat)
  422. if !FileManager.default.fileExists(atPath: imageURL.path) || !FileManager.default.fileExists(atPath: videoURL.path){
  423. let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.light)
  424. let blurEffectView = UIVisualEffectView(effect: blurEffect)
  425. blurEffectView.frame = CGRect(x: 0, y: 0, width: imageThumb.frame.size.width, height: imageThumb.frame.size.height)
  426. blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
  427. let imageDownload = UIImageView(image: UIImage(systemName: "arrow.down.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 50, weight: .bold, scale: .default)))
  428. imageThumb.addSubview(blurEffectView)
  429. imageThumb.addSubview(imageDownload)
  430. imageDownload.tintColor = .black.withAlphaComponent(0.3)
  431. imageDownload.translatesAutoresizingMaskIntoConstraints = false
  432. imageDownload.centerXAnchor.constraint(equalTo: imageThumb.centerXAnchor).isActive = true
  433. imageDownload.centerYAnchor.constraint(equalTo: imageThumb.centerYAnchor).isActive = true
  434. }
  435. }
  436. if (videoChat != "") {
  437. let imagePlay = UIImageView(image: UIImage(systemName: "play.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .bold, scale: .default))?.imageWithInsets(insets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))?.withTintColor(.white))
  438. imagePlay.circle()
  439. imageThumb.addSubview(imagePlay)
  440. imagePlay.backgroundColor = .black.withAlphaComponent(0.3)
  441. imagePlay.translatesAutoresizingMaskIntoConstraints = false
  442. imagePlay.centerXAnchor.constraint(equalTo: imageThumb.centerXAnchor).isActive = true
  443. imagePlay.centerYAnchor.constraint(equalTo: imageThumb.centerYAnchor).isActive = true
  444. }
  445. if (dataMessages[indexPath.row]["progress"] as! Double != 100.0 && dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
  446. let container = UIView()
  447. imageThumb.addSubview(container)
  448. container.translatesAutoresizingMaskIntoConstraints = false
  449. container.bottomAnchor.constraint(equalTo: imageThumb.bottomAnchor, constant: -10).isActive = true
  450. container.leadingAnchor.constraint(equalTo: imageThumb.leadingAnchor, constant: 10).isActive = true
  451. container.widthAnchor.constraint(equalToConstant: 30).isActive = true
  452. container.heightAnchor.constraint(equalToConstant: 30).isActive = true
  453. let circlePath = UIBezierPath(arcCenter: CGPoint(x: 10, y: 20), radius: 15, startAngle: -(.pi / 2), endAngle: .pi * 2, clockwise: true)
  454. let trackShape = CAShapeLayer()
  455. trackShape.path = circlePath.cgPath
  456. trackShape.fillColor = UIColor.black.withAlphaComponent(0.3).cgColor
  457. trackShape.lineWidth = 3
  458. trackShape.strokeColor = UIColor.mainColor.withAlphaComponent(0.3).cgColor
  459. container.backgroundColor = .clear
  460. container.layer.addSublayer(trackShape)
  461. let shapeLoading = CAShapeLayer()
  462. shapeLoading.path = circlePath.cgPath
  463. shapeLoading.fillColor = UIColor.clear.cgColor
  464. shapeLoading.lineWidth = 3
  465. shapeLoading.strokeEnd = 0
  466. shapeLoading.strokeColor = UIColor.mainColor.cgColor
  467. container.layer.addSublayer(shapeLoading)
  468. let imageupload = UIImageView(image: UIImage(systemName: "arrow.up", withConfiguration: UIImage.SymbolConfiguration(pointSize: 10, weight: .bold, scale: .default)))
  469. imageupload.tintColor = .white
  470. container.addSubview(imageupload)
  471. imageupload.translatesAutoresizingMaskIntoConstraints = false
  472. imageupload.bottomAnchor.constraint(equalTo: imageThumb.bottomAnchor, constant: -10).isActive = true
  473. imageupload.leadingAnchor.constraint(equalTo: imageThumb.leadingAnchor, constant: 10).isActive = true
  474. imageupload.widthAnchor.constraint(equalToConstant: 20).isActive = true
  475. imageupload.heightAnchor.constraint(equalToConstant: 20).isActive = true
  476. }
  477. let objectTap = ObjectGesture(target: self, action: #selector(contentMessageTapped(_:)))
  478. imageThumb.isUserInteractionEnabled = true
  479. imageThumb.addGestureRecognizer(objectTap)
  480. objectTap.image_id = imageChat
  481. objectTap.video_id = videoChat
  482. objectTap.imageView = imageThumb
  483. objectTap.indexPath = indexPath
  484. }
  485. if (fileChat != "") {
  486. topMarginText.constant = topMarginText.constant + 55
  487. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  488. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  489. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  490. let arrExtFile = (textChat?.components(separatedBy: "|")[0])?.split(separator: ".")
  491. let finalExtFile = arrExtFile![arrExtFile!.count - 1]
  492. if let dirPath = paths.first {
  493. let fileURL = URL(fileURLWithPath: dirPath).appendingPathComponent(fileChat)
  494. if let dataFile = try? Data(contentsOf: fileURL) {
  495. var sizeOfFile = Int(dataFile.count / 1000000)
  496. if (sizeOfFile < 1) {
  497. sizeOfFile = Int(dataFile.count / 1000)
  498. if (finalExtFile.count > 4) {
  499. messageText.text = "\(sizeOfFile) kB \u{2022} TXT"
  500. }else {
  501. messageText.text = "\(sizeOfFile) kB \u{2022} \(finalExtFile.uppercased())"
  502. }
  503. } else {
  504. if (finalExtFile.count > 4) {
  505. messageText.text = "\(sizeOfFile) MB \u{2022} TXT"
  506. }else {
  507. messageText.text = "\(sizeOfFile) MB \u{2022} \(finalExtFile.uppercased())"
  508. }
  509. }
  510. } else {
  511. messageText.text = ""
  512. }
  513. }
  514. containerMessage.addSubview(containerViewFile)
  515. containerViewFile.translatesAutoresizingMaskIntoConstraints = false
  516. containerViewFile.topAnchor.constraint(equalTo: containerMessage.topAnchor, constant: 32).isActive = true
  517. containerViewFile.leadingAnchor.constraint(equalTo: containerMessage.leadingAnchor, constant: 15).isActive = true
  518. containerViewFile.bottomAnchor.constraint(equalTo:messageText.topAnchor, constant: -5).isActive = true
  519. containerViewFile.trailingAnchor.constraint(equalTo: containerMessage.trailingAnchor, constant: -15).isActive = true
  520. containerViewFile.heightAnchor.constraint(equalToConstant: 50).isActive = true
  521. containerViewFile.backgroundColor = .black.withAlphaComponent(0.2)
  522. containerViewFile.layer.cornerRadius = 5.0
  523. containerViewFile.clipsToBounds = true
  524. let imageFile = UIImageView(image: UIImage(systemName: "doc.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .bold, scale: .default)))
  525. containerViewFile.addSubview(imageFile)
  526. let nameFile = UILabel()
  527. containerViewFile.addSubview(nameFile)
  528. imageFile.translatesAutoresizingMaskIntoConstraints = false
  529. imageFile.leadingAnchor.constraint(equalTo: containerViewFile.leadingAnchor, constant: 5).isActive = true
  530. imageFile.trailingAnchor.constraint(equalTo: nameFile.leadingAnchor, constant: -5).isActive = true
  531. imageFile.centerYAnchor.constraint(equalTo: containerViewFile.centerYAnchor).isActive = true
  532. imageFile.widthAnchor.constraint(equalToConstant: 30).isActive = true
  533. imageFile.heightAnchor.constraint(equalToConstant: 30).isActive = true
  534. imageFile.tintColor = .docColor
  535. nameFile.translatesAutoresizingMaskIntoConstraints = false
  536. nameFile.centerYAnchor.constraint(equalTo: containerViewFile.centerYAnchor).isActive = true
  537. nameFile.widthAnchor.constraint(lessThanOrEqualToConstant: 200).isActive = true
  538. nameFile.font = UIFont.systemFont(ofSize: 12, weight: .medium)
  539. nameFile.textColor = .white
  540. nameFile.text = textChat?.components(separatedBy: "|")[0]
  541. if (dataMessages[indexPath.row]["progress"] as! Double != 100.0) {
  542. let containerLoading = UIView()
  543. containerViewFile.addSubview(containerLoading)
  544. containerLoading.translatesAutoresizingMaskIntoConstraints = false
  545. containerLoading.centerYAnchor.constraint(equalTo: containerViewFile.centerYAnchor).isActive = true
  546. containerLoading.leadingAnchor.constraint(equalTo: nameFile.trailingAnchor, constant: 5).isActive = true
  547. containerLoading.trailingAnchor.constraint(equalTo: containerViewFile.trailingAnchor, constant: -5).isActive = true
  548. containerLoading.widthAnchor.constraint(equalToConstant: 30).isActive = true
  549. containerLoading.heightAnchor.constraint(equalToConstant: 30).isActive = true
  550. let circlePath = UIBezierPath(arcCenter: CGPoint(x: 15, y: 15), radius: 10, startAngle: -(.pi / 2), endAngle: .pi * 2, clockwise: true)
  551. let trackShape = CAShapeLayer()
  552. trackShape.path = circlePath.cgPath
  553. trackShape.fillColor = UIColor.clear.cgColor
  554. trackShape.lineWidth = 5
  555. trackShape.strokeColor = UIColor.mainColor.withAlphaComponent(0.3).cgColor
  556. containerLoading.layer.addSublayer(trackShape)
  557. let shapeLoading = CAShapeLayer()
  558. shapeLoading.path = circlePath.cgPath
  559. shapeLoading.fillColor = UIColor.clear.cgColor
  560. shapeLoading.lineWidth = 3
  561. shapeLoading.strokeEnd = 0
  562. shapeLoading.strokeColor = UIColor.mainColor.cgColor
  563. containerLoading.layer.addSublayer(shapeLoading)
  564. let imageupload = UIImageView(image: UIImage(systemName: "arrow.up", withConfiguration: UIImage.SymbolConfiguration(pointSize: 10, weight: .bold, scale: .default)))
  565. imageupload.tintColor = .white
  566. containerLoading.addSubview(imageupload)
  567. imageupload.translatesAutoresizingMaskIntoConstraints = false
  568. imageupload.centerYAnchor.constraint(equalTo: containerLoading.centerYAnchor).isActive = true
  569. imageupload.centerXAnchor.constraint(equalTo: containerLoading.centerXAnchor).isActive = true
  570. } else {
  571. nameFile.trailingAnchor.constraint(equalTo: containerViewFile.trailingAnchor, constant: -5).isActive = true
  572. }
  573. let objectTap = ObjectGesture(target: self, action: #selector(contentMessageTapped(_:)))
  574. containerViewFile.addGestureRecognizer(objectTap)
  575. objectTap.containerFile = containerViewFile
  576. objectTap.labelFile = nameFile
  577. objectTap.file_id = fileChat
  578. objectTap.indexPath = indexPath
  579. }
  580. return cellMessage
  581. }
  582. func getData() {
  583. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  584. if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id FROM MESSAGE where is_stared=1 order by server_date asc") {
  585. while cursorData.next() {
  586. var row: [String: Any?] = [:]
  587. row["message_id"] = cursorData.string(forColumnIndex: 0)
  588. row["f_pin"] = cursorData.string(forColumnIndex: 1)
  589. row["l_pin"] = cursorData.string(forColumnIndex: 2)
  590. row["message_scope_id"] = cursorData.string(forColumnIndex: 3)
  591. row["server_date"] = cursorData.string(forColumnIndex: 4)
  592. row["status"] = cursorData.string(forColumnIndex: 5)
  593. row["message_text"] = cursorData.string(forColumnIndex: 6)
  594. row["audio_id"] = cursorData.string(forColumnIndex: 7)
  595. row["video_id"] = cursorData.string(forColumnIndex: 8)
  596. row["image_id"] = cursorData.string(forColumnIndex: 9)
  597. row["thumb_id"] = cursorData.string(forColumnIndex: 10)
  598. row["read_receipts"] = cursorData.int(forColumnIndex: 11)
  599. row["chat_id"] = cursorData.string(forColumnIndex: 12)
  600. row["file_id"] = cursorData.string(forColumnIndex: 13)
  601. row["attachment_flag"] = cursorData.string(forColumnIndex: 14)
  602. row["reff_id"] = cursorData.string(forColumnIndex: 15)
  603. row["lock"] = cursorData.string(forColumnIndex: 16)
  604. row["is_stared"] = cursorData.string(forColumnIndex: 17)
  605. row["blog_id"] = cursorData.string(forColumnIndex: 18)
  606. if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status FROM MESSAGE_STATUS WHERE message_id='\(row["message_id"] as! String)'") {
  607. while cursorStatus.next() {
  608. row["status"] = cursorStatus.string(forColumnIndex: 0)
  609. }
  610. cursorStatus.close()
  611. }
  612. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  613. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  614. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  615. if let dirPath = paths.first {
  616. let videoURL = URL(fileURLWithPath: dirPath).appendingPathComponent(row["video_id"] as! String)
  617. let fileURL = URL(fileURLWithPath: dirPath).appendingPathComponent(row["file_id"] as! String)
  618. if ((row["video_id"] as! String) != "") {
  619. if FileManager.default.fileExists(atPath: videoURL.path){
  620. row["progress"] = 100.0
  621. } else {
  622. row["progress"] = 0.0
  623. }
  624. } else {
  625. if FileManager.default.fileExists(atPath: fileURL.path){
  626. row["progress"] = 100.0
  627. } else {
  628. row["progress"] = 0.0
  629. }
  630. }
  631. }
  632. row["chat_date"] = chatDate(stringDate: row["server_date"] as! String, messageId: row["message_id"] as! String)
  633. dataMessages.append(row)
  634. }
  635. cursorData.close()
  636. }
  637. })
  638. }
  639. private func chatDate(stringDate: String, messageId: String) -> String {
  640. let date = Date(milliseconds: Int64(stringDate)!)
  641. let calendar = Calendar.current
  642. if (calendar.isDateInToday(date)) {
  643. if !dataDates.contains("Today".localized()){
  644. dataDates.append("Today".localized())
  645. }
  646. return "Today".localized()
  647. } else {
  648. let startOfNow = calendar.startOfDay(for: Date())
  649. let startOfTimeStamp = calendar.startOfDay(for: date)
  650. let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
  651. let day = -(components.day!)
  652. if day == 1{
  653. if !dataDates.contains("Yesterday".localized()){
  654. dataDates.append("Yesterday".localized())
  655. }
  656. return "Yesterday".localized()
  657. } else if day < 7 {
  658. if !dataDates.contains("\(day) " + "days".localized() + " " + "ago".localized()){
  659. dataDates.append("\(day) " + "days".localized() + " " + "ago".localized())
  660. }
  661. return "\(day) " + "days".localized() + " " + "ago".localized()
  662. } else {
  663. let formatter = DateFormatter()
  664. formatter.dateFormat = "dd MMMM yyyy"
  665. formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
  666. let stringFormat = formatter.string(from: date as Date)
  667. if !dataDates.contains(stringFormat){
  668. dataDates.append(stringFormat)
  669. }
  670. return stringFormat
  671. }
  672. }
  673. }
  674. @objc func contentMessageTapped(_ sender: ObjectGesture) {
  675. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  676. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  677. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  678. if (sender.image_id != "") {
  679. if let dirPath = paths.first {
  680. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(sender.image_id)
  681. if FileManager.default.fileExists(atPath: imageURL.path) {
  682. let image = UIImage(contentsOfFile: imageURL.path)
  683. let previewImageVC = PreviewAttachmentImageVideo(nibName: "PreviewAttachmentImageVideo", bundle: Bundle.resourceBundle(for: DigiX.self))
  684. previewImageVC.image = image
  685. previewImageVC.isHiddenTextField = true
  686. previewImageVC.modalPresentationStyle = .custom
  687. previewImageVC.modalTransitionStyle = .crossDissolve
  688. self.present(previewImageVC, animated: true, completion: nil)
  689. } else {
  690. for view in sender.imageView.subviews {
  691. if view is UIImageView {
  692. view.removeFromSuperview()
  693. }
  694. }
  695. let activityIndicator = UIActivityIndicatorView(style: .large)
  696. activityIndicator.color = .mainColor
  697. activityIndicator.hidesWhenStopped = true
  698. activityIndicator.center = CGPoint(x:sender.imageView.frame.width/2,
  699. y: sender.imageView.frame.height/2)
  700. activityIndicator.startAnimating()
  701. sender.imageView.addSubview(activityIndicator)
  702. Download().start(forKey: sender.image_id) { (name, progress) in
  703. guard progress == 100 else {
  704. return
  705. }
  706. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(sender.image_id)
  707. let image = UIImage(contentsOfFile: imageURL.path)
  708. let save = UserDefaults.standard.bool(forKey: "saveToGallery")
  709. if save {
  710. UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)
  711. }
  712. DispatchQueue.main.async {
  713. activityIndicator.stopAnimating()
  714. self.tableChatView.reloadData()
  715. }
  716. }
  717. }
  718. }
  719. } else if (sender.video_id != "") {
  720. if let dirPath = paths.first {
  721. let videoURL = URL(fileURLWithPath: dirPath).appendingPathComponent(sender.video_id)
  722. if FileManager.default.fileExists(atPath: videoURL.path) {
  723. let player = AVPlayer(url: videoURL as URL)
  724. let playerVC = AVPlayerViewController()
  725. playerVC.modalPresentationStyle = .custom
  726. playerVC.player = player
  727. self.present(playerVC, animated: true, completion: nil)
  728. } else {
  729. for view in sender.imageView.subviews {
  730. if view is UIImageView {
  731. view.removeFromSuperview()
  732. }
  733. }
  734. let container = UIView()
  735. sender.imageView.addSubview(container)
  736. container.translatesAutoresizingMaskIntoConstraints = false
  737. container.centerXAnchor.constraint(equalTo: sender.imageView.centerXAnchor).isActive = true
  738. container.centerYAnchor.constraint(equalTo: sender.imageView.centerYAnchor).isActive = true
  739. container.widthAnchor.constraint(equalToConstant: 50).isActive = true
  740. container.heightAnchor.constraint(equalToConstant: 50).isActive = true
  741. let circlePath = UIBezierPath(arcCenter: CGPoint(x: 25, y: 25), radius: 20, startAngle: -(.pi / 2), endAngle: .pi * 2, clockwise: true)
  742. let trackShape = CAShapeLayer()
  743. trackShape.path = circlePath.cgPath
  744. trackShape.fillColor = UIColor.clear.cgColor
  745. trackShape.lineWidth = 10
  746. trackShape.strokeColor = UIColor.mainColor.withAlphaComponent(0.3).cgColor
  747. container.backgroundColor = .clear
  748. container.layer.addSublayer(trackShape)
  749. let shapeLoading = CAShapeLayer()
  750. shapeLoading.path = circlePath.cgPath
  751. shapeLoading.fillColor = UIColor.clear.cgColor
  752. shapeLoading.lineWidth = 10
  753. shapeLoading.strokeEnd = 0
  754. shapeLoading.strokeColor = UIColor.mainColor.cgColor
  755. container.layer.addSublayer(shapeLoading)
  756. let imageDownload = UIImageView(image: UIImage(systemName: "arrow.down", withConfiguration: UIImage.SymbolConfiguration(pointSize: 10, weight: .bold, scale: .default)))
  757. imageDownload.tintColor = .white
  758. container.addSubview(imageDownload)
  759. imageDownload.translatesAutoresizingMaskIntoConstraints = false
  760. imageDownload.centerXAnchor.constraint(equalTo: sender.imageView.centerXAnchor).isActive = true
  761. imageDownload.centerYAnchor.constraint(equalTo: sender.imageView.centerYAnchor).isActive = true
  762. imageDownload.widthAnchor.constraint(equalToConstant: 30).isActive = true
  763. imageDownload.heightAnchor.constraint(equalToConstant: 30).isActive = true
  764. Download().start(forKey: sender.video_id) { (name, progress) in
  765. DispatchQueue.main.async {
  766. guard progress == 100 else {
  767. shapeLoading.strokeEnd = CGFloat(progress / 100)
  768. return
  769. }
  770. let save = UserDefaults.standard.bool(forKey: "saveToGallery")
  771. if save {
  772. let videoURL = URL(fileURLWithPath: dirPath).appendingPathComponent(sender.video_id)
  773. PHPhotoLibrary.shared().performChanges({
  774. PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
  775. }) { saved, error in
  776. }
  777. }
  778. let idx = self.dataMessages.firstIndex(where: { $0["video_id"] as! String == sender.video_id})
  779. if idx != nil {
  780. self.dataMessages[idx!]["progress"] = progress
  781. self.tableChatView.reloadRows(at: [sender.indexPath], with: .none)
  782. }
  783. }
  784. }
  785. }
  786. }
  787. } else if (sender.file_id != "") {
  788. if let dirPath = paths.first {
  789. let fileURL = URL(fileURLWithPath: dirPath).appendingPathComponent(sender.file_id)
  790. if FileManager.default.fileExists(atPath: fileURL.path) {
  791. self.previewItem = fileURL as NSURL
  792. let previewController = QLPreviewController()
  793. let rightBarButton = UIBarButtonItem()
  794. previewController.navigationItem.rightBarButtonItem = rightBarButton
  795. previewController.dataSource = self
  796. previewController.modalPresentationStyle = .custom
  797. self.show(previewController, sender: nil)
  798. } else {
  799. for view in sender.containerFile.subviews {
  800. if !(view is UIImageView) && !(view is UILabel) {
  801. view.removeFromSuperview()
  802. }
  803. }
  804. let containerLoading = UIView()
  805. sender.containerFile.addSubview(containerLoading)
  806. containerLoading.translatesAutoresizingMaskIntoConstraints = false
  807. containerLoading.centerYAnchor.constraint(equalTo: sender.containerFile.centerYAnchor).isActive = true
  808. containerLoading.leadingAnchor.constraint(equalTo: sender.labelFile.trailingAnchor, constant: 5).isActive = true
  809. containerLoading.trailingAnchor.constraint(equalTo: sender.containerFile.trailingAnchor, constant: -5).isActive = true
  810. containerLoading.widthAnchor.constraint(equalToConstant: 30).isActive = true
  811. containerLoading.heightAnchor.constraint(equalToConstant: 30).isActive = true
  812. let circlePath = UIBezierPath(arcCenter: CGPoint(x: 15, y: 15), radius: 10, startAngle: -(.pi / 2), endAngle: .pi * 2, clockwise: true)
  813. let trackShape = CAShapeLayer()
  814. trackShape.path = circlePath.cgPath
  815. trackShape.fillColor = UIColor.clear.cgColor
  816. trackShape.lineWidth = 5
  817. trackShape.strokeColor = UIColor.mainColor.withAlphaComponent(0.3).cgColor
  818. containerLoading.layer.addSublayer(trackShape)
  819. let shapeLoading = CAShapeLayer()
  820. shapeLoading.path = circlePath.cgPath
  821. shapeLoading.fillColor = UIColor.clear.cgColor
  822. shapeLoading.lineWidth = 3
  823. shapeLoading.strokeEnd = 0
  824. shapeLoading.strokeColor = UIColor.mainColor.cgColor
  825. containerLoading.layer.addSublayer(shapeLoading)
  826. let imageupload = UIImageView(image: UIImage(systemName: "arrow.down", withConfiguration: UIImage.SymbolConfiguration(pointSize: 10, weight: .bold, scale: .default)))
  827. imageupload.tintColor = .white
  828. containerLoading.addSubview(imageupload)
  829. imageupload.translatesAutoresizingMaskIntoConstraints = false
  830. imageupload.centerYAnchor.constraint(equalTo: containerLoading.centerYAnchor).isActive = true
  831. imageupload.centerXAnchor.constraint(equalTo: containerLoading.centerXAnchor).isActive = true
  832. Download().start(forKey: sender.file_id) { (name, progress) in
  833. DispatchQueue.main.async {
  834. guard progress == 100 else {
  835. shapeLoading.strokeEnd = CGFloat(progress / 100)
  836. return
  837. }
  838. let idx = self.dataMessages.firstIndex(where: { $0["file_id"] as! String == sender.file_id})
  839. if idx != nil {
  840. self.dataMessages[idx!]["progress"] = progress
  841. self.tableChatView.reloadRows(at: [sender.indexPath], with: .none)
  842. }
  843. }
  844. }
  845. }
  846. }
  847. } else {
  848. DispatchQueue.main.async {
  849. let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as! String == sender.message_id})
  850. if idx == nil {
  851. return
  852. }
  853. let section = self.dataDates.firstIndex(of: self.dataMessages[idx!]["chat_date"] as! String)
  854. if section == nil {
  855. return
  856. }
  857. let row = self.dataMessages.filter({ $0["chat_date"] as! String == self.dataDates[section!]}).firstIndex(where: { $0["message_id"] as! String == self.dataMessages[idx!]["message_id"] as! String})
  858. if row == nil {
  859. return
  860. }
  861. let indexPath = IndexPath(row: row!, section: section!)
  862. self.tableChatView.scrollToRow(at: indexPath, at: .middle, animated: true)
  863. DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
  864. if let cell = self.tableChatView.cellForRow(at: indexPath) {
  865. let containerMessage = cell.contentView.subviews[0]
  866. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  867. if (self.dataMessages[idx!]["f_pin"] as? String == idMe) {
  868. containerMessage.backgroundColor = .mainColor.withAlphaComponent(0.3)
  869. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
  870. if (self.dataMessages[idx!]["attachment_flag"] as? String == "11") {
  871. containerMessage.backgroundColor = .clear
  872. } else {
  873. containerMessage.backgroundColor = .mainColor
  874. }
  875. }
  876. } else {
  877. containerMessage.backgroundColor = .grayColor.withAlphaComponent(0.3)
  878. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
  879. if (self.dataMessages[idx!]["attachment_flag"] as? String == "11") {
  880. containerMessage.backgroundColor = .clear
  881. } else {
  882. containerMessage.backgroundColor = .grayColor
  883. }
  884. }
  885. }
  886. }
  887. }
  888. }
  889. }
  890. }
  891. func getDataProfile(f_pin: String) -> [String: String]{
  892. var data: [String: String] = [:]
  893. Database().database?.inTransaction({ fmdb, rollback in
  894. if let c = Database().getRecords(fmdb: fmdb, query: "select first_name || ' ' || last_name, image_id from BUDDY where f_pin = '\(f_pin)'"), c.next() {
  895. data["name"] = c.string(forColumnIndex: 0)!.trimmingCharacters(in: .whitespacesAndNewlines)
  896. data["image_id"] = c.string(forColumnIndex: 1)!
  897. c.close()
  898. }
  899. else if f_pin == "-999" {
  900. data["name"] = "Bot".localized()
  901. data["image_id"] = "pb_powered"
  902. }
  903. else {
  904. data["name"] = "Unknown".localized()
  905. data["image_id"] = ""
  906. }
  907. })
  908. return data
  909. }
  910. private func getDataProfileFromMessageId(message_id: String) -> [String: String]{
  911. var data: [String: String] = [:]
  912. Database().database?.inTransaction({ fmdb, rollback in
  913. if let c = Database().getRecords(fmdb: fmdb, query: "select f_display_name from MESSAGE where message_id = '\(message_id)'"), c.next() {
  914. data["name"] = c.string(forColumnIndex: 0)!
  915. c.close()
  916. } else {
  917. data["name"] = "Unknown".localized()
  918. data["image_id"] = ""
  919. }
  920. })
  921. return data
  922. }
  923. public func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
  924. let indexPath = self.tableChatView.indexPathForRow(at: interaction.view!.convert(location, to: self.tableChatView))
  925. let dataMessages = self.dataMessages.filter({ $0["chat_date"] as! String == dataDates[indexPath!.section]})
  926. let star = UIAction(title: "Unstar".localized(), image: UIImage(systemName: "star.fill"), handler: {(_) in
  927. DispatchQueue.global().async {
  928. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  929. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  930. "is_stared" : 0
  931. ], _where: "message_id = '\(dataMessages[indexPath!.row]["message_id"] as! String)'")
  932. })
  933. }
  934. let idx = self.dataMessages.firstIndex(where: { $0["message_id"] as! String == dataMessages[indexPath!.row]["message_id"] as! String})
  935. if idx != nil{
  936. self.dataMessages[idx!]["is_stared"] = "0"
  937. }
  938. self.dataMessages.remove(at: idx!)
  939. self.tableChatView.deleteRows(at: [indexPath!], with: .fade)
  940. if self.dataMessages.filter({ $0["chat_date"] as! String == dataMessages[indexPath!.row]["chat_date"] as! String }).count == 0 {
  941. self.dataDates.remove(at: indexPath!.section)
  942. self.tableChatView.deleteSections(IndexSet(integer: indexPath!.section), with: .fade)
  943. }
  944. })
  945. let forward = UIAction(title: "Forward".localized(), image: UIImage(systemName: "arrowshape.turn.up.right.fill"), handler: {(_) in
  946. let navigationController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactChatNav") as! UINavigationController
  947. navigationController.modalPresentationStyle = .custom
  948. navigationController.navigationBar.tintColor = .white
  949. navigationController.navigationBar.barTintColor = .mainColor
  950. navigationController.navigationBar.isTranslucent = false
  951. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  952. navigationController.navigationBar.barStyle = .black
  953. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  954. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  955. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  956. navigationController.navigationBar.titleTextAttributes = textAttributes
  957. navigationController.view.backgroundColor = .mainColor
  958. if let controller = navigationController.viewControllers.first as? ContactChatViewController {
  959. controller.isChooser = { [weak self] scope, pin in
  960. if scope == "3" {
  961. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  962. editorPersonalVC.unique_l_pin = pin
  963. editorPersonalVC.dataMessageForward = [dataMessages[indexPath!.row]]
  964. self?.navigationController?.replaceAllViewController(with: editorPersonalVC, animated: true)
  965. } else {
  966. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  967. editorGroupVC.unique_l_pin = pin
  968. editorGroupVC.dataMessageForward = [dataMessages[indexPath!.row]]
  969. self?.navigationController?.replaceAllViewController(with: editorGroupVC, animated: true)
  970. }
  971. }
  972. }
  973. self.present(navigationController, animated: true, completion: nil)
  974. })
  975. let copy = UIAction(title: "Copy".localized(), image: UIImage(systemName: "doc.on.doc.fill"), handler: {(_) in
  976. if (dataMessages[indexPath!.row]["attachment_flag"] as! String == "0") {
  977. DispatchQueue.main.async {
  978. var text = ""
  979. let stringDate = (dataMessages[indexPath!.row]["server_date"] as! String)
  980. let date = Date(milliseconds: Int64(stringDate)!)
  981. let formatterDate = DateFormatter()
  982. let formatterTime = DateFormatter()
  983. formatterDate.dateFormat = "dd/MM/yy"
  984. formatterDate.locale = NSLocale(localeIdentifier: "id") as Locale?
  985. formatterTime.dateFormat = "HH:mm"
  986. formatterTime.locale = NSLocale(localeIdentifier: "id") as Locale?
  987. let dataProfile = self.getDataProfileFromMessageId(message_id: dataMessages[indexPath!.row]["message_id"] as! String)
  988. if text.isEmpty {
  989. text = "*[\(formatterDate.string(from: date as Date)) \(formatterTime.string(from: date as Date))] \(dataProfile["name"]!):*\n\(dataMessages[indexPath!.row]["message_text"] as! String)"
  990. } else {
  991. text = text + "\n\n*[\(formatterDate.string(from: date as Date)) \(formatterTime.string(from: date as Date))] \(dataProfile["name"]!):*\n\(dataMessages[indexPath!.row]["message_text"] as! String)"
  992. }
  993. text = text + "\n\n\nchat " + "Powered by Telkomsel".localized()
  994. DispatchQueue.main.async {
  995. UIPasteboard.general.string = text
  996. self.showToast(message: "Text coppied to clipboard".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
  997. }
  998. }
  999. } else {
  1000. DispatchQueue.main.async {
  1001. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  1002. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  1003. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  1004. if let dirPath = paths.first {
  1005. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(dataMessages[indexPath!.row]["image_id"] as! String)
  1006. if FileManager.default.fileExists(atPath: imageURL.path) {
  1007. let image = UIImage(contentsOfFile: imageURL.path)
  1008. UIPasteboard.general.image = image
  1009. self.showToast(message: "Image coppied to clipboard".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
  1010. }
  1011. }
  1012. }
  1013. }
  1014. })
  1015. var children: [UIMenuElement] = [star, forward, copy]
  1016. // let copyOption = self.copyOption(indexPath: indexPath!)
  1017. if self.dataMessages[indexPath!.row]["f_pin"] as! String == "-999" {
  1018. children = [star]
  1019. } else if !(dataMessages[indexPath!.row]["image_id"] as! String).isEmpty || !(dataMessages[indexPath!.row]["video_id"] as! String).isEmpty || !(dataMessages[indexPath!.row]["file_id"] as! String).isEmpty || dataMessages[indexPath!.row]["attachment_flag"] as! String == "11" {
  1020. children = [star, forward]
  1021. }
  1022. return UIContextMenuConfiguration(identifier: nil,
  1023. previewProvider: nil) { _ in
  1024. UIMenu(title: "", children: children)
  1025. }
  1026. }
  1027. private func copyOption(indexPath: IndexPath) -> UIMenu {
  1028. let ratingButtonTitles = ["Text".localized(), "Image".localized()]
  1029. let dataMessages = self.dataMessages.filter({ $0["chat_date"] as! String == dataDates[indexPath.section]})
  1030. let copyActions = ratingButtonTitles
  1031. .enumerated()
  1032. .map { index, title in
  1033. return UIAction(
  1034. title: title,
  1035. identifier: nil,
  1036. handler: {(_) in if (index == 0) {
  1037. DispatchQueue.main.async {
  1038. UIPasteboard.general.string = dataMessages[indexPath.row]["message_text"] as? String
  1039. self.showToast(message: "Text coppied to clipboard".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
  1040. }
  1041. } else {
  1042. DispatchQueue.main.async {
  1043. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  1044. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  1045. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  1046. if let dirPath = paths.first {
  1047. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(dataMessages[indexPath.row]["image_id"] as! String)
  1048. if FileManager.default.fileExists(atPath: imageURL.path) {
  1049. let image = UIImage(contentsOfFile: imageURL.path)
  1050. UIPasteboard.general.image = image
  1051. self.showToast(message: "Image coppied to clipboard".localized(), font: UIFont.systemFont(ofSize: 12, weight: .medium), controller: self)
  1052. }
  1053. }
  1054. }
  1055. }})
  1056. }
  1057. return UIMenu(
  1058. title: "Copy".localized(),
  1059. image: UIImage(systemName: "doc.on.doc.fill"),
  1060. children: copyActions)
  1061. }
  1062. @objc private func cancelDocumentPreview(sender: navigationQLPreviewDocument) {
  1063. sender.navigation.dismiss(animated: true, completion: nil)
  1064. }
  1065. @objc func segmentedControlValueChanged(_ sender: segmentedControllerObject) {
  1066. switch sender.selectedSegmentIndex {
  1067. case 0:
  1068. sender.navigation.viewControllers[0].children[1].view.isHidden = true
  1069. break;
  1070. case 1:
  1071. sender.navigation.viewControllers[0].children[1].view.isHidden = false
  1072. break;
  1073. default:
  1074. break;
  1075. }
  1076. }
  1077. public func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
  1078. 1
  1079. }
  1080. public func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
  1081. return self.previewItem as QLPreviewItem
  1082. }
  1083. public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  1084. let message = dataMessages[indexPath.row]
  1085. if let attachmentFlag = message["attachment_flag"], let attachmentFlag = attachmentFlag as? String {
  1086. if attachmentFlag == "27" {
  1087. let streamingController = QmeraCreateStreamingViewController()
  1088. streamingController.isJoin = true
  1089. if let messageText = message["message_text"],
  1090. let messageText = messageText as? String,
  1091. var json = try! JSONSerialization.jsonObject(with: messageText.data(using: String.Encoding.utf8)!, options: []) as? [String: Any] {
  1092. if json["blog"] == nil {
  1093. json["blog"] = message["blog_id"] ?? nil
  1094. }
  1095. streamingController.data = json
  1096. }
  1097. let streamingNav = UINavigationController(rootViewController: streamingController)
  1098. streamingNav.modalPresentationStyle = .custom
  1099. streamingNav.navigationBar.barTintColor = .mainColor
  1100. streamingNav.navigationBar.tintColor = .white
  1101. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  1102. streamingNav.navigationBar.titleTextAttributes = textAttributes
  1103. streamingNav.navigationBar.isTranslucent = false
  1104. navigationController?.present(streamingNav, animated: true, completion: nil)
  1105. }
  1106. }
  1107. }
  1108. }