ListGroupImages.swift 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. //
  2. // ListGroupImages.swift
  3. // NexilisLite
  4. //
  5. // Created by Akhmad Al Qindi Irsyam on 28/07/23.
  6. //
  7. import UIKit
  8. import Popover
  9. class ListGroupImages: UIViewController, UITableViewDataSource, UITableViewDelegate {
  10. var listGroupingImages: [ImageGrouping]!
  11. var imageTapped: Int!
  12. var titleName: String!
  13. let tableViewImages = UITableView()
  14. var isInitiator = false
  15. var forwardSession = false
  16. var deleteSession = false
  17. var tableViewPopOver = UITableView()
  18. var popover: Popover!
  19. var startYVisible: CGFloat!
  20. var endYVisible: CGFloat!
  21. var indexSelected = 0
  22. var updateEditor: (([ImageGrouping], [String: Any?], Bool) -> ())?
  23. var isSelectAll = false
  24. var viewMultipleSelect = UIView()
  25. var constraintBottomViewMultipleSelect: NSLayoutConstraint!
  26. let centeredTitleView = CenteredTitleSubtitleView(frame: CGRect(x: 0, y: 0, width: 200, height: 44))
  27. var isPersonal = true
  28. override func viewDidLoad() {
  29. super.viewDidLoad()
  30. view.backgroundColor = .white
  31. centeredTitleView.titleLabel.text = titleName
  32. centeredTitleView.subtitleLabel.text = String(listGroupingImages.count) + " " + "images".localized()
  33. navigationItem.titleView = centeredTitleView
  34. let selectButton = UIBarButtonItem(title: "Select".localized(), style: .plain, target: self, action: #selector(selectAction))
  35. selectButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .normal)
  36. navigationItem.rightBarButtonItem = selectButton
  37. tableViewImages.register(UITableViewCell.self, forCellReuseIdentifier: "cellGrupingImages")
  38. tableViewImages.dataSource = self
  39. tableViewImages.delegate = self
  40. tableViewImages.separatorStyle = .none
  41. self.view.addSubview(tableViewImages)
  42. tableViewImages.anchor(top: self.view.safeAreaLayoutGuide.topAnchor, left: self.view.safeAreaLayoutGuide.leftAnchor, bottom: self.view.safeAreaLayoutGuide.bottomAnchor, right: self.view.safeAreaLayoutGuide.rightAnchor)
  43. DispatchQueue.main.async {[self] in
  44. tableViewImages.scrollToRow(at: IndexPath(row: imageTapped, section: 0), at: .top, animated: false)
  45. }
  46. let center: NotificationCenter = NotificationCenter.default
  47. center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil)
  48. self.view.addSubview(viewMultipleSelect)
  49. viewMultipleSelect.backgroundColor = .white.withAlphaComponent(0.9)
  50. viewMultipleSelect.anchor(left: self.view.safeAreaLayoutGuide.leftAnchor, right: self.view.safeAreaLayoutGuide.rightAnchor, height: 50)
  51. constraintBottomViewMultipleSelect = viewMultipleSelect.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: 50)
  52. constraintBottomViewMultipleSelect.isActive = true
  53. }
  54. @objc func onStatusChat(notification: NSNotification) {
  55. DispatchQueue.main.async { [self] in
  56. let data:[AnyHashable : Any] = notification.userInfo!
  57. if let dataMessage = data["message"] as? TMessage {
  58. var messageId = dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
  59. messageId = messageId.contains("-2") ? String(messageId.split(separator: ",")[1]) : messageId
  60. if let idx = listGroupingImages.firstIndex(where: { $0.messageId == messageId }) {
  61. listGroupingImages[idx].status = dataMessage.getBody(key: CoreMessage_TMessageKey.STATUS)
  62. listGroupingImages[idx].dataMessage["status"] = dataMessage.getBody(key: CoreMessage_TMessageKey.STATUS)
  63. tableViewImages.reloadRows(at: [IndexPath(row: idx, section: 0)], with: .none)
  64. }
  65. }
  66. }
  67. }
  68. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  69. if tableView == tableViewPopOver {
  70. return 5
  71. }
  72. return listGroupingImages.count
  73. }
  74. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  75. if tableView == tableViewPopOver {
  76. let cell = tableView.dequeueReusableCell(withIdentifier: "cellPopOver", for: indexPath as IndexPath)
  77. var content = cell.defaultContentConfiguration()
  78. content.textProperties.font = UIFont.systemFont(ofSize: 14)
  79. content.imageProperties.tintColor = .black
  80. switch indexPath.row {
  81. case 0:
  82. if listGroupingImages[indexSelected].dataMessage["is_stared"] as! String == "1" {
  83. content.image = UIImage(systemName: "star.slash.fill")
  84. content.text = "Unstar".localized()
  85. } else {
  86. content.image = UIImage(systemName: "star.fill")
  87. content.text = "Star".localized()
  88. }
  89. case 1:
  90. content.image = UIImage(systemName: "arrowshape.turn.up.left.fill")
  91. content.text = "Reply".localized()
  92. case 2:
  93. content.image = UIImage(systemName: "arrowshape.turn.up.right.fill")
  94. content.text = "Forward".localized()
  95. case 3:
  96. content.image = UIImage(systemName: "info.circle.fill")
  97. content.text = "Info".localized()
  98. default:
  99. content.image = UIImage(systemName: "trash.fill")
  100. content.text = "Delete".localized()
  101. }
  102. cell.contentConfiguration = content
  103. return cell
  104. }
  105. let cell = tableView.dequeueReusableCell(withIdentifier: "cellGrupingImages", for: indexPath as IndexPath)
  106. cell.contentView.subviews.forEach({ $0.removeFromSuperview() })
  107. cell.backgroundColor = .clear
  108. cell.selectionStyle = .none
  109. let containerImages = UIImageView()
  110. containerImages.contentMode = .scaleAspectFit
  111. cell.contentView.addSubview(containerImages)
  112. containerImages.anchor(top: cell.contentView.topAnchor, left: cell.contentView.leftAnchor, right: cell.contentView.rightAnchor, height: ListGroupImages.getImageSize(image: listGroupingImages[indexPath.row].thumbId, screenWidth: UIScreen.main.bounds.width, screenHeight: UIScreen.main.bounds.height)!.height)
  113. if !forwardSession && !deleteSession {
  114. let longPressRecognizer = LongPressImageVIew(target: self, action: #selector(handleLongPress(_:)))
  115. longPressRecognizer.imageView = containerImages
  116. longPressRecognizer.index = indexPath.row
  117. containerImages.isUserInteractionEnabled = true
  118. containerImages.addGestureRecognizer(longPressRecognizer)
  119. }
  120. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  121. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  122. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  123. if let dirPath = paths.first {
  124. let imageId = listGroupingImages[indexPath.row].imageId
  125. let thumbId = listGroupingImages[indexPath.row].thumbId
  126. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(imageId)
  127. DispatchQueue.main.async {
  128. let image : UIImage? = {
  129. if let img = Nexilis.imageCache.object(forKey: imageId as NSString) {
  130. return img
  131. }
  132. else if let img = UIImage(contentsOfFile: imageURL.path)?.resize(target: CGSize(width: 1000, height: 1000)) {
  133. Nexilis.imageCache.setObject(img, forKey: imageId as NSString)
  134. return img
  135. }
  136. return nil
  137. }()
  138. if image == nil {
  139. let thumbURL = URL(fileURLWithPath: dirPath).appendingPathComponent(self.listGroupingImages[indexPath.row].thumbId)
  140. let image : UIImage? = {
  141. if let img = Nexilis.imageCache.object(forKey: thumbId as NSString) {
  142. return img
  143. }
  144. else if let img = UIImage(contentsOfFile: thumbURL.path)?.resize(target: CGSize(width: 500, height: 500)) {
  145. Nexilis.imageCache.setObject(img, forKey: thumbId as NSString)
  146. return img
  147. }
  148. return nil
  149. }()
  150. containerImages.image = image
  151. } else {
  152. containerImages.image = image
  153. }
  154. }
  155. if !FileManager.default.fileExists(atPath: imageURL.path) {
  156. let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.light)
  157. let blurEffectView = UIVisualEffectView(effect: blurEffect)
  158. blurEffectView.frame = CGRect(x: 0, y: 0, width: containerImages.frame.size.width, height: containerImages.frame.size.height)
  159. blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
  160. containerImages.addSubview(blurEffectView)
  161. let imageDownload = UIImageView(image: UIImage(systemName: "arrow.down.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 50, weight: .bold, scale: .default)))
  162. containerImages.addSubview(blurEffectView)
  163. containerImages.addSubview(imageDownload)
  164. imageDownload.tintColor = .black.withAlphaComponent(0.3)
  165. imageDownload.translatesAutoresizingMaskIntoConstraints = false
  166. imageDownload.centerXAnchor.constraint(equalTo: containerImages.centerXAnchor).isActive = true
  167. imageDownload.centerYAnchor.constraint(equalTo: containerImages.centerYAnchor).isActive = true
  168. }
  169. }
  170. let containerTimeStatus = UIView()
  171. containerImages.addSubview(containerTimeStatus)
  172. containerTimeStatus.anchor(bottom: containerImages.bottomAnchor, right: containerImages.rightAnchor, height: 20)
  173. let widthcontainerTimeStatus = containerTimeStatus.widthAnchor.constraint(equalToConstant: 60)
  174. widthcontainerTimeStatus.isActive = true
  175. containerTimeStatus.layer.cornerRadius = 5.0
  176. containerTimeStatus.layer.masksToBounds = true
  177. containerTimeStatus.backgroundColor = .black.withAlphaComponent(0.25)
  178. let timeInImage = UILabel()
  179. containerTimeStatus.addSubview(timeInImage)
  180. let date = Date(milliseconds: Int64(listGroupingImages[indexPath.row].time) ?? 100)
  181. let formatter = DateFormatter()
  182. formatter.dateFormat = "HH:mm"
  183. formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
  184. timeInImage.text = formatter.string(from: date as Date)
  185. timeInImage.textColor = .white
  186. timeInImage.font = UIFont.systemFont(ofSize: 12, weight: .medium)
  187. if isInitiator {
  188. let statusInImage = UIImageView()
  189. containerTimeStatus.addSubview(statusInImage)
  190. statusInImage.anchor(right: containerTimeStatus.rightAnchor, centerY: containerTimeStatus.centerYAnchor, width: 20, height: 20)
  191. if listGroupingImages[indexPath.row].status == "1" || listGroupingImages[indexPath.row].status == "2" {
  192. statusInImage.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.white)
  193. } else if listGroupingImages[indexPath.row].status == "3" {
  194. statusInImage.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.white)
  195. } else {
  196. statusInImage.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.systemBlue)
  197. }
  198. timeInImage.anchor(right: statusInImage.leftAnchor, centerY: containerTimeStatus.centerYAnchor, height: 15)
  199. } else {
  200. timeInImage.anchor(right: containerTimeStatus.rightAnchor, paddingRight: 5, centerY: containerTimeStatus.centerYAnchor, height: 20)
  201. widthcontainerTimeStatus.constant = widthcontainerTimeStatus.constant - 10
  202. }
  203. if listGroupingImages[indexPath.row].dataMessage["is_stared"] as! String == "1" {
  204. let iconStar = UIImageView()
  205. containerTimeStatus.addSubview(iconStar)
  206. iconStar.anchor(right: timeInImage.leftAnchor, paddingRight: 2, centerY: containerTimeStatus.centerYAnchor, width: 20, height: 20)
  207. widthcontainerTimeStatus.constant = widthcontainerTimeStatus.constant + 20
  208. iconStar.image = UIImage(systemName: "star.fill")
  209. iconStar.tintColor = .white
  210. }
  211. if deleteSession || forwardSession {
  212. let containerSelect = UIView()
  213. containerImages.addSubview(containerSelect)
  214. containerSelect.anchor(top: containerImages.topAnchor, left: containerImages.leftAnchor, bottom: containerImages.bottomAnchor, right: containerImages.rightAnchor)
  215. let iconSelected = UIImageView(frame: CGRect(x: 0, y: 0, width: 25.0, height: 25.0))
  216. iconSelected.backgroundColor = .lightGray.withAlphaComponent(0.3)
  217. iconSelected.layer.borderWidth = 2
  218. iconSelected.layer.borderColor = UIColor.black.cgColor
  219. iconSelected.layer.cornerRadius = 12.5
  220. iconSelected.layer.masksToBounds = true
  221. iconSelected.tintColor = .black
  222. containerSelect.addSubview(iconSelected)
  223. iconSelected.anchor(top: containerSelect.topAnchor, left: containerSelect.leftAnchor, paddingTop: 10, paddingLeft: 10, width: 25.0, height: 25.0)
  224. if listGroupingImages[indexPath.row].isSelected {
  225. containerSelect.backgroundColor = .white.withAlphaComponent(0.2)
  226. iconSelected.image = UIImage(systemName: "checkmark.circle.fill")
  227. }
  228. }
  229. return cell
  230. }
  231. func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  232. if tableView == tableViewImages {
  233. return ListGroupImages.getImageSize(image: listGroupingImages[indexPath.row].thumbId, screenWidth: UIScreen.main.bounds.width, screenHeight: UIScreen.main.bounds.height)!.height + 15
  234. }
  235. return UITableView.automaticDimension
  236. }
  237. func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  238. if tableView == tableViewPopOver {
  239. popover.dismiss()
  240. switch indexPath.row {
  241. case 0:
  242. popover.dismiss()
  243. if listGroupingImages[indexSelected].dataMessage["is_stared"] as! String == "0" {
  244. DispatchQueue.global().async { [self] in
  245. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  246. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  247. "is_stared" : 1
  248. ], _where: "message_id = '\(listGroupingImages[indexSelected].messageId)'")
  249. })
  250. }
  251. listGroupingImages[indexSelected].dataMessage["is_stared"] = "1"
  252. } else {
  253. DispatchQueue.global().async { [self] in
  254. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  255. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  256. "is_stared" : 0
  257. ], _where: "message_id = '\(listGroupingImages[indexSelected].messageId)'")
  258. })
  259. }
  260. listGroupingImages[indexSelected].dataMessage["is_stared"] = "0"
  261. }
  262. tableViewImages.reloadRows(at: [IndexPath(row: indexSelected, section: 0)], with: .none)
  263. updateEditor!(listGroupingImages, [:], false)
  264. case 1:
  265. popover.dismiss()
  266. self.navigationController?.popViewController(animated: true)
  267. updateEditor!([], listGroupingImages[indexSelected].dataMessage, false)
  268. case 2:
  269. popover.dismiss()
  270. listGroupingImages[indexSelected].isSelected = true
  271. selectActions(isDeleteSession: false)
  272. case 3:
  273. popover.dismiss()
  274. let messageInfoVC = MessageInfo()
  275. messageInfoVC.data = listGroupingImages[indexSelected].dataMessage
  276. if isPersonal {
  277. messageInfoVC.dataPerson = listGroupingImages[indexSelected].dataPerson
  278. } else {
  279. messageInfoVC.dataGroup = listGroupingImages[indexSelected].dataGroup
  280. messageInfoVC.isPersonal = false
  281. }
  282. self.navigationController?.pushViewController(messageInfoVC, animated: true)
  283. default :
  284. popover.dismiss()
  285. listGroupingImages[indexSelected].isSelected = true
  286. selectActions(isDeleteSession: true)
  287. }
  288. } else if deleteSession || forwardSession {
  289. if listGroupingImages[indexPath.row].isSelected {
  290. listGroupingImages[indexPath.row].isSelected = false
  291. } else {
  292. listGroupingImages[indexPath.row].isSelected = true
  293. }
  294. if listGroupingImages.filter({ $0.isSelected }).count != listGroupingImages.count && isSelectAll {
  295. changetoLeftBarButton(isSelectAllButton: true)
  296. } else if listGroupingImages.filter({ $0.isSelected }).count == listGroupingImages.count && !isSelectAll {
  297. changetoLeftBarButton(isSelectAllButton: false)
  298. }
  299. viewMultipleSelect.subviews.forEach({ $0.removeFromSuperview() })
  300. addSubviewMultipleSelect()
  301. tableView.reloadRows(at: [indexPath], with: .none)
  302. } else {
  303. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  304. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  305. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  306. if let dirPath = paths.first {
  307. let imageId = listGroupingImages[indexPath.row].imageId
  308. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(imageId)
  309. if !FileManager.default.fileExists(atPath: imageURL.path) {
  310. Download().startHTTP(forKey: listGroupingImages[indexPath.row].imageId) { (name, progress) in
  311. guard progress == 100 else {
  312. return
  313. }
  314. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(self.listGroupingImages[indexPath.row].imageId)
  315. let image = UIImage(contentsOfFile: imageURL.path)
  316. let save = UserDefaults.standard.bool(forKey: "saveToGallery")
  317. if save {
  318. UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)
  319. }
  320. DispatchQueue.main.async { [self] in
  321. tableView.reloadRows(at: [indexPath], with: .none)
  322. updateEditor!(listGroupingImages, [:], false)
  323. }
  324. }
  325. }
  326. }
  327. }
  328. }
  329. func scrollViewDidScroll(_ scrollView: UIScrollView) {
  330. let visibleRect = CGRect(origin: scrollView.contentOffset, size: scrollView.bounds.size)
  331. let visibleTableViewRect = tableViewImages.convert(visibleRect, from: tableViewImages)
  332. let startY = visibleTableViewRect.origin.y
  333. let endY = startY + visibleTableViewRect.size.height
  334. startYVisible = startY
  335. endYVisible = endY
  336. }
  337. @objc func handleLongPress(_ gestureRecognizer: LongPressImageVIew) {
  338. if gestureRecognizer.state == .began {
  339. indexSelected = gestureRecognizer.index
  340. let contentOffset = tableViewImages.contentOffset
  341. let location = gestureRecognizer.location(in: tableViewImages)
  342. let xTouch = location.x - contentOffset.x
  343. var yTouch = location.y - contentOffset.y + 100
  344. let boundary = startYVisible != nil ? (endYVisible - startYVisible) / 2 - 50 : (UIScreen.main.bounds.height - 64) / 2 - 50
  345. let yTouchDiff = startYVisible != nil ? location.y - startYVisible : location.y - 0.0
  346. tableViewPopOver = UITableView(frame: CGRect(x: 0, y: 10, width: 140, height: 220))
  347. popover = Popover()
  348. if yTouchDiff >= boundary {
  349. yTouch = location.y - contentOffset.y + 20
  350. tableViewPopOver = UITableView(frame: CGRect(x: 0, y: 0, width: 140, height: 220))
  351. popover.popoverType = .up
  352. }
  353. tableViewPopOver.register(UITableViewCell.self, forCellReuseIdentifier: "cellPopOver")
  354. tableViewPopOver.dataSource = self
  355. tableViewPopOver.delegate = self
  356. tableViewPopOver.layoutMargins = UIEdgeInsets.zero
  357. tableViewPopOver.separatorInset = UIEdgeInsets.zero
  358. tableViewPopOver.isScrollEnabled = false
  359. let viewTable = UITableView(frame: CGRect(x: 0, y: 0, width: 140, height: 220))
  360. viewTable.addSubview(tableViewPopOver)
  361. let touchPoint = CGPoint( x: xTouch, y: yTouch)
  362. popover.show(viewTable, point: touchPoint)
  363. UINotificationFeedbackGenerator().notificationOccurred(.success)
  364. }
  365. }
  366. @objc func selectAction() {
  367. selectActions(isDeleteSession: true)
  368. }
  369. func selectActions(isDeleteSession: Bool) {
  370. self.navigationItem.setHidesBackButton(true, animated: true)
  371. changetoLeftBarButton(isSelectAllButton: true)
  372. let doneButton = UIBarButtonItem(title: "Done".localized(), style: .plain, target: self, action: #selector(doneAction))
  373. doneButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16)], for: .normal)
  374. navigationItem.rightBarButtonItem = doneButton
  375. deleteSession = isDeleteSession
  376. forwardSession = !isDeleteSession
  377. constraintBottomViewMultipleSelect.constant = 0
  378. UIView.animate(withDuration: 0.35, animations: {
  379. self.view.layoutIfNeeded()
  380. })
  381. addSubviewMultipleSelect()
  382. tableViewImages.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50, right: 0)
  383. tableViewImages.reloadData()
  384. }
  385. @objc func selectAllAction() {
  386. listGroupingImages.forEach({ $0.isSelected = true })
  387. changetoLeftBarButton(isSelectAllButton: false)
  388. viewMultipleSelect.subviews.forEach({ $0.removeFromSuperview() })
  389. addSubviewMultipleSelect()
  390. tableViewImages.reloadData()
  391. }
  392. @objc func deselectAllAction() {
  393. listGroupingImages.forEach({ $0.isSelected = false })
  394. changetoLeftBarButton(isSelectAllButton: true)
  395. viewMultipleSelect.subviews.forEach({ $0.removeFromSuperview() })
  396. addSubviewMultipleSelect()
  397. tableViewImages.reloadData()
  398. }
  399. @objc func doneAction() {
  400. navigationItem.leftBarButtonItem = nil
  401. let selectButton = UIBarButtonItem(title: "Select".localized(), style: .plain, target: self, action: #selector(selectAction))
  402. selectButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .normal)
  403. navigationItem.rightBarButtonItem = selectButton
  404. self.navigationItem.setHidesBackButton(false, animated: true)
  405. listGroupingImages.forEach({ $0.isSelected = false })
  406. deleteSession = false
  407. forwardSession = false
  408. tableViewImages.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  409. constraintBottomViewMultipleSelect.constant = 50
  410. viewMultipleSelect.subviews.forEach({ $0.removeFromSuperview() })
  411. UIView.animate(withDuration: 0.35, animations: {
  412. self.view.layoutIfNeeded()
  413. })
  414. tableViewImages.reloadData()
  415. }
  416. func changetoLeftBarButton(isSelectAllButton: Bool) {
  417. if isSelectAllButton {
  418. let selectAllButton = UIBarButtonItem(title: "Select All".localized(), style: .plain, target: self, action: #selector(selectAllAction))
  419. selectAllButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .normal)
  420. navigationItem.leftBarButtonItem = selectAllButton
  421. isSelectAll = false
  422. } else {
  423. let deselectAllButton = UIBarButtonItem(title: "Deselect All".localized(), style: .plain, target: self, action: #selector(deselectAllAction))
  424. deselectAllButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .normal)
  425. navigationItem.leftBarButtonItem = deselectAllButton
  426. isSelectAll = true
  427. }
  428. }
  429. func addSubviewMultipleSelect() {
  430. viewMultipleSelect.addTopBorder(with: .lightGray, andWidth: 1)
  431. let container = UIView()
  432. viewMultipleSelect.addSubview(container)
  433. container.translatesAutoresizingMaskIntoConstraints = false
  434. NSLayoutConstraint.activate([
  435. container.leadingAnchor.constraint(equalTo: viewMultipleSelect.leadingAnchor),
  436. container.trailingAnchor.constraint(equalTo:viewMultipleSelect.trailingAnchor),
  437. container.bottomAnchor.constraint(equalTo: viewMultipleSelect.bottomAnchor),
  438. container.heightAnchor.constraint(equalToConstant: 50)
  439. ])
  440. let title = UILabel()
  441. container.addSubview(title)
  442. title.translatesAutoresizingMaskIntoConstraints = false
  443. NSLayoutConstraint.activate([
  444. title.centerXAnchor.constraint(equalTo: container.centerXAnchor),
  445. title.centerYAnchor.constraint(equalTo:container.centerYAnchor),
  446. ])
  447. let countSelected = listGroupingImages.filter({ $0.isSelected }).count
  448. title.text = "\(countSelected) " + "Selected".localized()
  449. title.textColor = .mainColor
  450. title.font = UIFont.systemFont(ofSize: 15.0).bold
  451. let button = UIImageView()
  452. container.addSubview(button)
  453. button.translatesAutoresizingMaskIntoConstraints = false
  454. NSLayoutConstraint.activate([
  455. button.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 15),
  456. button.centerYAnchor.constraint(equalTo:container.centerYAnchor),
  457. button.widthAnchor.constraint(equalToConstant: 30),
  458. button.heightAnchor.constraint(equalToConstant: 30),
  459. ])
  460. if forwardSession {
  461. button.image = UIImage(systemName: "arrowshape.turn.up.right")
  462. if countSelected == 0 {
  463. button.tintColor = .gray
  464. } else {
  465. button.tintColor = .mainColor
  466. }
  467. } else if deleteSession {
  468. button.image = UIImage(systemName: "trash")
  469. if countSelected == 0 {
  470. button.tintColor = .gray
  471. } else {
  472. button.tintColor = .red
  473. }
  474. }
  475. let buttonGesture = UITapGestureRecognizer(target: self, action: #selector(sessionAction))
  476. button.isUserInteractionEnabled = true
  477. button.addGestureRecognizer(buttonGesture)
  478. }
  479. @objc func sessionAction() {
  480. if forwardSession {
  481. let tempDataMessages = listGroupingImages.filter({ $0.isSelected })
  482. var dataMessages: [[String: Any?]] = []
  483. for i in 0..<tempDataMessages.count {
  484. dataMessages.append(tempDataMessages[i].dataMessage)
  485. }
  486. let contactChatNav = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactChatNav") as! UINavigationController
  487. Utils.addBackground(view: contactChatNav.view)
  488. contactChatNav.modalPresentationStyle = .custom
  489. contactChatNav.navigationBar.tintColor = .white
  490. contactChatNav.navigationBar.barTintColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  491. contactChatNav.navigationBar.isTranslucent = false
  492. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  493. contactChatNav.navigationBar.titleTextAttributes = textAttributes
  494. contactChatNav.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  495. if let controller = contactChatNav.viewControllers.first as? ContactChatViewController {
  496. controller.isChooser = { [weak self] scope, pin in
  497. if scope == "3" {
  498. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  499. editorPersonalVC.unique_l_pin = pin
  500. editorPersonalVC.dataMessageForward = dataMessages
  501. self?.navigationController?.replaceAllViewController(with: editorPersonalVC, animated: true)
  502. } else {
  503. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  504. editorGroupVC.unique_l_pin = pin
  505. editorGroupVC.dataMessageForward = dataMessages
  506. self?.navigationController?.replaceAllViewController(with: editorGroupVC, animated: true)
  507. }
  508. }
  509. }
  510. self.present(contactChatNav, animated: true, completion: nil)
  511. } else if deleteSession {
  512. let tempDataMessages = listGroupingImages.filter({ $0.isSelected })
  513. let countSelected = tempDataMessages.count
  514. if countSelected == 0 {
  515. return
  516. }
  517. let alertController = LibAlertController(title: "Delete".localized() + " \(countSelected) " + "messages?", message: nil, preferredStyle: .actionSheet)
  518. if let action = self.actionDelete(for: "me", title: "Delete".localized() + " \(countSelected) " + "For Me".localized(), dataMessages: tempDataMessages) {
  519. alertController.addAction(action)
  520. }
  521. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  522. let dataStatusRead = tempDataMessages.filter({ $0.status == "4" })
  523. if tempDataMessages[0].dataMessage["f_pin"] as? String == idMe && dataStatusRead.count == 0 {
  524. if let action = self.actionDelete(for: "everyone", title: "Delete".localized() + " \(countSelected) " + "For Everyone".localized(), dataMessages: tempDataMessages) {
  525. alertController.addAction(action)
  526. }
  527. }
  528. alertController.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
  529. self.present(alertController, animated: true)
  530. }
  531. }
  532. private func actionDelete(for type: String, title: String, dataMessages: [ImageGrouping]) -> UIAlertAction? {
  533. return UIAlertAction(title: title, style: .destructive) { [unowned self] _ in
  534. let tempDataDelete = listGroupingImages
  535. for i in 0..<dataMessages.count {
  536. if (type == "me") {
  537. if isPersonal {
  538. self.deleteMessage(l_pin: dataMessages[i].lPin, message_id: dataMessages[i].messageId, scope: "3", type: "1", chat: "")
  539. } else {
  540. self.deleteMessage(l_pin: dataMessages[i].dataGroup["group_id"] as! String, message_id: dataMessages[i].messageId, scope: "4", type: "1", chat: dataMessages[i].dataTopic["chat_id"] as! String)
  541. }
  542. listGroupingImages.removeAll(where: { $0.messageId == dataMessages[i].messageId })
  543. } else {
  544. if isPersonal {
  545. self.deleteMessage(l_pin: dataMessages[i].lPin, message_id: dataMessages[i].messageId, scope: "3", type: "2", chat: "")
  546. } else {
  547. self.deleteMessage(l_pin: dataMessages[i].dataGroup["group_id"] as! String, message_id: dataMessages[i].messageId, scope: "4", type: "2", chat: dataMessages[i].dataTopic["chat_id"] as! String)
  548. }
  549. if let idxTemp = tempDataDelete!.firstIndex(where: { $0.messageId == dataMessages[i].messageId}) {
  550. tempDataDelete![idxTemp].dataMessage["lock"] = "1"
  551. }
  552. listGroupingImages.removeAll(where: { $0.messageId == dataMessages[i].messageId })
  553. }
  554. }
  555. centeredTitleView.subtitleLabel.text = String(listGroupingImages.count) + " " + "images".localized()
  556. updateEditor!(type == "me" ? listGroupingImages : tempDataDelete!, [:], true)
  557. doneAction()
  558. }
  559. }
  560. private func deleteMessage(l_pin: String, message_id: String, scope: String, type: String, chat: String) {
  561. let tmessage = CoreMessage_TMessageBank.deleteMessage(l_pin: l_pin, messageId: message_id, scope: scope, type: type, chat: chat)
  562. Nexilis.deleteQueueMessage(message: tmessage)
  563. }
  564. static func getImageSize(image: String, screenWidth: CGFloat, screenHeight: CGFloat) -> CGSize? {
  565. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  566. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  567. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  568. if let dirPath = paths.first {
  569. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(image)
  570. var imagePath = UIImage(contentsOfFile: imageURL.path)
  571. if imagePath == nil {
  572. Download().startHTTP(forKey: image) { (name, progress) in
  573. guard progress == 100 else {
  574. return
  575. }
  576. }
  577. imagePath = UIImage(named: "Send-Image", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  578. }
  579. let imageWidth = imagePath!.size.width
  580. let imageHeight = imagePath!.size.height
  581. // Calculate the aspect ratio of the image
  582. let aspectRatio = imageWidth / imageHeight
  583. // Calculate the size to display the image while maintaining its aspect ratio
  584. var displayWidth: CGFloat = 0.0
  585. var displayHeight: CGFloat = 0.0
  586. if imageWidth > imageHeight {
  587. // Landscape image
  588. displayWidth = screenWidth
  589. displayHeight = screenWidth / aspectRatio
  590. } else {
  591. // Portrait or square image
  592. displayHeight = screenHeight
  593. displayWidth = screenHeight * aspectRatio
  594. }
  595. return CGSize(width: displayWidth, height: displayHeight)
  596. }
  597. return nil
  598. }
  599. }
  600. class CenteredTitleSubtitleView: UIView {
  601. let titleLabel: UILabel = {
  602. let label = UILabel()
  603. label.textAlignment = .center
  604. label.font = UIFont.boldSystemFont(ofSize: 18)
  605. label.textColor = .white
  606. return label
  607. }()
  608. let subtitleLabel: UILabel = {
  609. let label = UILabel()
  610. label.textAlignment = .center
  611. label.font = UIFont.systemFont(ofSize: 14)
  612. label.textColor = .lightGray
  613. return label
  614. }()
  615. override init(frame: CGRect) {
  616. super.init(frame: frame)
  617. setupSubviews()
  618. }
  619. required init?(coder: NSCoder) {
  620. super.init(coder: coder)
  621. setupSubviews()
  622. }
  623. private func setupSubviews() {
  624. addSubview(titleLabel)
  625. addSubview(subtitleLabel)
  626. // Add any constraints or frames you prefer
  627. // Here's an example using autolayout anchors
  628. titleLabel.translatesAutoresizingMaskIntoConstraints = false
  629. titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
  630. titleLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
  631. subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
  632. subtitleLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
  633. subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true
  634. }
  635. }
  636. class LongPressImageVIew: UILongPressGestureRecognizer {
  637. var imageView = UIImageView()
  638. var index = 0
  639. }