ListGroupImages.swift 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  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. }
  162. }
  163. let containerTimeStatus = UIView()
  164. containerImages.addSubview(containerTimeStatus)
  165. containerTimeStatus.anchor(bottom: containerImages.bottomAnchor, right: containerImages.rightAnchor, height: 20)
  166. let widthcontainerTimeStatus = containerTimeStatus.widthAnchor.constraint(equalToConstant: 60)
  167. widthcontainerTimeStatus.isActive = true
  168. containerTimeStatus.layer.cornerRadius = 5.0
  169. containerTimeStatus.layer.masksToBounds = true
  170. containerTimeStatus.backgroundColor = .black.withAlphaComponent(0.25)
  171. let timeInImage = UILabel()
  172. containerTimeStatus.addSubview(timeInImage)
  173. let date = Date(milliseconds: Int64(listGroupingImages[indexPath.row].time) ?? 100)
  174. let formatter = DateFormatter()
  175. formatter.dateFormat = "HH:mm"
  176. formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
  177. timeInImage.text = formatter.string(from: date as Date)
  178. timeInImage.textColor = .white
  179. timeInImage.font = UIFont.systemFont(ofSize: 12, weight: .medium)
  180. if isInitiator {
  181. let statusInImage = UIImageView()
  182. containerTimeStatus.addSubview(statusInImage)
  183. statusInImage.anchor(right: containerTimeStatus.rightAnchor, centerY: containerTimeStatus.centerYAnchor, width: 20, height: 20)
  184. if listGroupingImages[indexPath.row].status == "1" || listGroupingImages[indexPath.row].status == "2" {
  185. statusInImage.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.white)
  186. } else if listGroupingImages[indexPath.row].status == "3" {
  187. statusInImage.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.white)
  188. } else {
  189. statusInImage.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.systemBlue)
  190. }
  191. timeInImage.anchor(right: statusInImage.leftAnchor, centerY: containerTimeStatus.centerYAnchor, height: 15)
  192. } else {
  193. timeInImage.anchor(right: containerTimeStatus.rightAnchor, paddingRight: 5, centerY: containerTimeStatus.centerYAnchor, height: 20)
  194. widthcontainerTimeStatus.constant = widthcontainerTimeStatus.constant - 10
  195. }
  196. if listGroupingImages[indexPath.row].dataMessage["is_stared"] as! String == "1" {
  197. let iconStar = UIImageView()
  198. containerTimeStatus.addSubview(iconStar)
  199. iconStar.anchor(right: timeInImage.leftAnchor, paddingRight: 2, centerY: containerTimeStatus.centerYAnchor, width: 20, height: 20)
  200. widthcontainerTimeStatus.constant = widthcontainerTimeStatus.constant + 20
  201. iconStar.image = UIImage(systemName: "star.fill")
  202. iconStar.tintColor = .white
  203. }
  204. if deleteSession || forwardSession {
  205. let containerSelect = UIView()
  206. containerImages.addSubview(containerSelect)
  207. containerSelect.anchor(top: containerImages.topAnchor, left: containerImages.leftAnchor, bottom: containerImages.bottomAnchor, right: containerImages.rightAnchor)
  208. let iconSelected = UIImageView(frame: CGRect(x: 0, y: 0, width: 25.0, height: 25.0))
  209. iconSelected.backgroundColor = .lightGray.withAlphaComponent(0.3)
  210. iconSelected.layer.borderWidth = 2
  211. iconSelected.layer.borderColor = UIColor.black.cgColor
  212. iconSelected.layer.cornerRadius = 12.5
  213. iconSelected.layer.masksToBounds = true
  214. iconSelected.tintColor = .black
  215. containerSelect.addSubview(iconSelected)
  216. iconSelected.anchor(top: containerSelect.topAnchor, left: containerSelect.leftAnchor, paddingTop: 10, paddingLeft: 10, width: 25.0, height: 25.0)
  217. if listGroupingImages[indexPath.row].isSelected {
  218. containerSelect.backgroundColor = .white.withAlphaComponent(0.2)
  219. iconSelected.image = UIImage(systemName: "checkmark.circle.fill")
  220. }
  221. }
  222. return cell
  223. }
  224. func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  225. if tableView == tableViewImages {
  226. return ListGroupImages.getImageSize(image: listGroupingImages[indexPath.row].thumbId, screenWidth: UIScreen.main.bounds.width, screenHeight: UIScreen.main.bounds.height)!.height + 15
  227. }
  228. return UITableView.automaticDimension
  229. }
  230. func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  231. if tableView == tableViewPopOver {
  232. popover.dismiss()
  233. switch indexPath.row {
  234. case 0:
  235. popover.dismiss()
  236. if listGroupingImages[indexSelected].dataMessage["is_stared"] as! String == "0" {
  237. DispatchQueue.global().async { [self] in
  238. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  239. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  240. "is_stared" : 1
  241. ], _where: "message_id = '\(listGroupingImages[indexSelected].messageId)'")
  242. })
  243. }
  244. listGroupingImages[indexSelected].dataMessage["is_stared"] = "1"
  245. } else {
  246. DispatchQueue.global().async { [self] in
  247. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  248. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  249. "is_stared" : 0
  250. ], _where: "message_id = '\(listGroupingImages[indexSelected].messageId)'")
  251. })
  252. }
  253. listGroupingImages[indexSelected].dataMessage["is_stared"] = "0"
  254. }
  255. tableViewImages.reloadRows(at: [IndexPath(row: indexSelected, section: 0)], with: .none)
  256. updateEditor!(listGroupingImages, [:], false)
  257. case 1:
  258. popover.dismiss()
  259. self.navigationController?.popViewController(animated: true)
  260. updateEditor!([], listGroupingImages[indexSelected].dataMessage, false)
  261. case 2:
  262. popover.dismiss()
  263. listGroupingImages[indexSelected].isSelected = true
  264. selectActions(isDeleteSession: false)
  265. case 3:
  266. popover.dismiss()
  267. let messageInfoVC = MessageInfo()
  268. messageInfoVC.data = listGroupingImages[indexSelected].dataMessage
  269. if isPersonal {
  270. messageInfoVC.dataPerson = listGroupingImages[indexSelected].dataPerson
  271. } else {
  272. messageInfoVC.dataGroup = listGroupingImages[indexSelected].dataGroup
  273. messageInfoVC.isPersonal = false
  274. }
  275. self.navigationController?.pushViewController(messageInfoVC, animated: true)
  276. default :
  277. popover.dismiss()
  278. listGroupingImages[indexSelected].isSelected = true
  279. selectActions(isDeleteSession: true)
  280. }
  281. } else if deleteSession || forwardSession {
  282. if listGroupingImages[indexPath.row].isSelected {
  283. listGroupingImages[indexPath.row].isSelected = false
  284. } else {
  285. listGroupingImages[indexPath.row].isSelected = true
  286. }
  287. if listGroupingImages.filter({ $0.isSelected }).count != listGroupingImages.count && isSelectAll {
  288. changetoLeftBarButton(isSelectAllButton: true)
  289. } else if listGroupingImages.filter({ $0.isSelected }).count == listGroupingImages.count && !isSelectAll {
  290. changetoLeftBarButton(isSelectAllButton: false)
  291. }
  292. viewMultipleSelect.subviews.forEach({ $0.removeFromSuperview() })
  293. addSubviewMultipleSelect()
  294. tableView.reloadRows(at: [indexPath], with: .none)
  295. }
  296. }
  297. func scrollViewDidScroll(_ scrollView: UIScrollView) {
  298. let visibleRect = CGRect(origin: scrollView.contentOffset, size: scrollView.bounds.size)
  299. let visibleTableViewRect = tableViewImages.convert(visibleRect, from: tableViewImages)
  300. let startY = visibleTableViewRect.origin.y
  301. let endY = startY + visibleTableViewRect.size.height
  302. startYVisible = startY
  303. endYVisible = endY
  304. }
  305. @objc func handleLongPress(_ gestureRecognizer: LongPressImageVIew) {
  306. if gestureRecognizer.state == .began {
  307. indexSelected = gestureRecognizer.index
  308. let contentOffset = tableViewImages.contentOffset
  309. let location = gestureRecognizer.location(in: tableViewImages)
  310. let xTouch = location.x - contentOffset.x
  311. var yTouch = location.y - contentOffset.y + 100
  312. let boundary = startYVisible != nil ? (endYVisible - startYVisible) / 2 - 50 : (UIScreen.main.bounds.height - 64) / 2 - 50
  313. let yTouchDiff = startYVisible != nil ? location.y - startYVisible : location.y - 0.0
  314. tableViewPopOver = UITableView(frame: CGRect(x: 0, y: 10, width: 140, height: 220))
  315. popover = Popover()
  316. if yTouchDiff >= boundary {
  317. yTouch = location.y - contentOffset.y + 20
  318. tableViewPopOver = UITableView(frame: CGRect(x: 0, y: 0, width: 140, height: 220))
  319. popover.popoverType = .up
  320. }
  321. tableViewPopOver.register(UITableViewCell.self, forCellReuseIdentifier: "cellPopOver")
  322. tableViewPopOver.dataSource = self
  323. tableViewPopOver.delegate = self
  324. tableViewPopOver.layoutMargins = UIEdgeInsets.zero
  325. tableViewPopOver.separatorInset = UIEdgeInsets.zero
  326. tableViewPopOver.isScrollEnabled = false
  327. let viewTable = UITableView(frame: CGRect(x: 0, y: 0, width: 140, height: 220))
  328. viewTable.addSubview(tableViewPopOver)
  329. let touchPoint = CGPoint( x: xTouch, y: yTouch)
  330. popover.show(viewTable, point: touchPoint)
  331. UINotificationFeedbackGenerator().notificationOccurred(.success)
  332. }
  333. }
  334. @objc func selectAction() {
  335. selectActions(isDeleteSession: true)
  336. }
  337. func selectActions(isDeleteSession: Bool) {
  338. self.navigationItem.setHidesBackButton(true, animated: true)
  339. changetoLeftBarButton(isSelectAllButton: true)
  340. let doneButton = UIBarButtonItem(title: "Done".localized(), style: .plain, target: self, action: #selector(doneAction))
  341. doneButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16)], for: .normal)
  342. navigationItem.rightBarButtonItem = doneButton
  343. deleteSession = isDeleteSession
  344. forwardSession = !isDeleteSession
  345. constraintBottomViewMultipleSelect.constant = 0
  346. UIView.animate(withDuration: 0.35, animations: {
  347. self.view.layoutIfNeeded()
  348. })
  349. addSubviewMultipleSelect()
  350. tableViewImages.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50, right: 0)
  351. tableViewImages.reloadData()
  352. }
  353. @objc func selectAllAction() {
  354. listGroupingImages.forEach({ $0.isSelected = true })
  355. changetoLeftBarButton(isSelectAllButton: false)
  356. viewMultipleSelect.subviews.forEach({ $0.removeFromSuperview() })
  357. addSubviewMultipleSelect()
  358. tableViewImages.reloadData()
  359. }
  360. @objc func deselectAllAction() {
  361. listGroupingImages.forEach({ $0.isSelected = false })
  362. changetoLeftBarButton(isSelectAllButton: true)
  363. viewMultipleSelect.subviews.forEach({ $0.removeFromSuperview() })
  364. addSubviewMultipleSelect()
  365. tableViewImages.reloadData()
  366. }
  367. @objc func doneAction() {
  368. navigationItem.leftBarButtonItem = nil
  369. let selectButton = UIBarButtonItem(title: "Select".localized(), style: .plain, target: self, action: #selector(selectAction))
  370. selectButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .normal)
  371. navigationItem.rightBarButtonItem = selectButton
  372. self.navigationItem.setHidesBackButton(false, animated: true)
  373. listGroupingImages.forEach({ $0.isSelected = false })
  374. deleteSession = false
  375. forwardSession = false
  376. tableViewImages.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  377. constraintBottomViewMultipleSelect.constant = 50
  378. viewMultipleSelect.subviews.forEach({ $0.removeFromSuperview() })
  379. UIView.animate(withDuration: 0.35, animations: {
  380. self.view.layoutIfNeeded()
  381. })
  382. tableViewImages.reloadData()
  383. }
  384. func changetoLeftBarButton(isSelectAllButton: Bool) {
  385. if isSelectAllButton {
  386. let selectAllButton = UIBarButtonItem(title: "Select All".localized(), style: .plain, target: self, action: #selector(selectAllAction))
  387. selectAllButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .normal)
  388. navigationItem.leftBarButtonItem = selectAllButton
  389. isSelectAll = false
  390. } else {
  391. let deselectAllButton = UIBarButtonItem(title: "Deselect All".localized(), style: .plain, target: self, action: #selector(deselectAllAction))
  392. deselectAllButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .normal)
  393. navigationItem.leftBarButtonItem = deselectAllButton
  394. isSelectAll = true
  395. }
  396. }
  397. func addSubviewMultipleSelect() {
  398. viewMultipleSelect.addTopBorder(with: .lightGray, andWidth: 1)
  399. let container = UIView()
  400. viewMultipleSelect.addSubview(container)
  401. container.translatesAutoresizingMaskIntoConstraints = false
  402. NSLayoutConstraint.activate([
  403. container.leadingAnchor.constraint(equalTo: viewMultipleSelect.leadingAnchor),
  404. container.trailingAnchor.constraint(equalTo:viewMultipleSelect.trailingAnchor),
  405. container.bottomAnchor.constraint(equalTo: viewMultipleSelect.bottomAnchor),
  406. container.heightAnchor.constraint(equalToConstant: 50)
  407. ])
  408. let title = UILabel()
  409. container.addSubview(title)
  410. title.translatesAutoresizingMaskIntoConstraints = false
  411. NSLayoutConstraint.activate([
  412. title.centerXAnchor.constraint(equalTo: container.centerXAnchor),
  413. title.centerYAnchor.constraint(equalTo:container.centerYAnchor),
  414. ])
  415. let countSelected = listGroupingImages.filter({ $0.isSelected }).count
  416. title.text = "\(countSelected) " + "Selected".localized()
  417. title.textColor = .mainColor
  418. title.font = UIFont.systemFont(ofSize: 15.0).bold
  419. let button = UIImageView()
  420. container.addSubview(button)
  421. button.translatesAutoresizingMaskIntoConstraints = false
  422. NSLayoutConstraint.activate([
  423. button.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 15),
  424. button.centerYAnchor.constraint(equalTo:container.centerYAnchor),
  425. button.widthAnchor.constraint(equalToConstant: 30),
  426. button.heightAnchor.constraint(equalToConstant: 30),
  427. ])
  428. if forwardSession {
  429. button.image = UIImage(systemName: "arrowshape.turn.up.right")
  430. if countSelected == 0 {
  431. button.tintColor = .gray
  432. } else {
  433. button.tintColor = .mainColor
  434. }
  435. } else if deleteSession {
  436. button.image = UIImage(systemName: "trash")
  437. if countSelected == 0 {
  438. button.tintColor = .gray
  439. } else {
  440. button.tintColor = .red
  441. }
  442. }
  443. let buttonGesture = UITapGestureRecognizer(target: self, action: #selector(sessionAction))
  444. button.isUserInteractionEnabled = true
  445. button.addGestureRecognizer(buttonGesture)
  446. }
  447. @objc func sessionAction() {
  448. if forwardSession {
  449. let tempDataMessages = listGroupingImages.filter({ $0.isSelected })
  450. var dataMessages: [[String: Any?]] = []
  451. for i in 0..<tempDataMessages.count {
  452. dataMessages.append(tempDataMessages[i].dataMessage)
  453. }
  454. let contactChatNav = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactChatNav") as! UINavigationController
  455. contactChatNav.modalPresentationStyle = .custom
  456. contactChatNav.navigationBar.tintColor = .white
  457. contactChatNav.navigationBar.barTintColor = .mainColor
  458. contactChatNav.navigationBar.isTranslucent = false
  459. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  460. contactChatNav.navigationBar.titleTextAttributes = textAttributes
  461. contactChatNav.view.backgroundColor = .mainColor
  462. if let controller = contactChatNav.viewControllers.first as? ContactChatViewController {
  463. controller.isChooser = { [weak self] scope, pin in
  464. if scope == "3" {
  465. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  466. editorPersonalVC.unique_l_pin = pin
  467. editorPersonalVC.dataMessageForward = dataMessages
  468. self?.navigationController?.replaceAllViewController(with: editorPersonalVC, animated: true)
  469. } else {
  470. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  471. editorGroupVC.unique_l_pin = pin
  472. editorGroupVC.dataMessageForward = dataMessages
  473. self?.navigationController?.replaceAllViewController(with: editorGroupVC, animated: true)
  474. }
  475. }
  476. }
  477. self.present(contactChatNav, animated: true, completion: nil)
  478. } else if deleteSession {
  479. let tempDataMessages = listGroupingImages.filter({ $0.isSelected })
  480. let countSelected = tempDataMessages.count
  481. if countSelected == 0 {
  482. return
  483. }
  484. let alertController = LibAlertController(title: "Delete".localized() + " \(countSelected) " + "messages?", message: nil, preferredStyle: .actionSheet)
  485. if let action = self.actionDelete(for: "me", title: "Delete".localized() + " \(countSelected) " + "For Me".localized(), dataMessages: tempDataMessages) {
  486. alertController.addAction(action)
  487. }
  488. let idMe = UserDefaults.standard.string(forKey: "me") as String?
  489. let dataStatusRead = tempDataMessages.filter({ $0.status == "4" })
  490. if tempDataMessages[0].dataMessage["f_pin"] as? String == idMe && dataStatusRead.count == 0 {
  491. if let action = self.actionDelete(for: "everyone", title: "Delete".localized() + " \(countSelected) " + "For Everyone".localized(), dataMessages: tempDataMessages) {
  492. alertController.addAction(action)
  493. }
  494. }
  495. alertController.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
  496. self.present(alertController, animated: true)
  497. }
  498. }
  499. private func actionDelete(for type: String, title: String, dataMessages: [ImageGrouping]) -> UIAlertAction? {
  500. return UIAlertAction(title: title, style: .destructive) { [unowned self] _ in
  501. let tempDataDelete = listGroupingImages
  502. for i in 0..<dataMessages.count {
  503. if (type == "me") {
  504. if isPersonal {
  505. self.deleteMessage(l_pin: dataMessages[i].lPin, message_id: dataMessages[i].messageId, scope: "3", type: "1", chat: "")
  506. } else {
  507. 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)
  508. }
  509. listGroupingImages.removeAll(where: { $0.messageId == dataMessages[i].messageId })
  510. } else {
  511. if isPersonal {
  512. self.deleteMessage(l_pin: dataMessages[i].lPin, message_id: dataMessages[i].messageId, scope: "3", type: "2", chat: "")
  513. } else {
  514. 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)
  515. }
  516. if let idxTemp = tempDataDelete!.firstIndex(where: { $0.messageId == dataMessages[i].messageId}) {
  517. tempDataDelete![idxTemp].dataMessage["lock"] = "1"
  518. }
  519. listGroupingImages.removeAll(where: { $0.messageId == dataMessages[i].messageId })
  520. }
  521. }
  522. centeredTitleView.subtitleLabel.text = String(listGroupingImages.count) + " " + "images".localized()
  523. updateEditor!(type == "me" ? listGroupingImages : tempDataDelete!, [:], true)
  524. doneAction()
  525. }
  526. }
  527. private func deleteMessage(l_pin: String, message_id: String, scope: String, type: String, chat: String) {
  528. let tmessage = CoreMessage_TMessageBank.deleteMessage(l_pin: l_pin, messageId: message_id, scope: scope, type: type, chat: chat)
  529. Nexilis.deleteQueueMessage(message: tmessage)
  530. }
  531. static func getImageSize(image: String, screenWidth: CGFloat, screenHeight: CGFloat) -> CGSize? {
  532. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  533. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  534. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  535. if let dirPath = paths.first {
  536. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(image)
  537. let image = UIImage(contentsOfFile: imageURL.path)
  538. let imageWidth = image!.size.width
  539. let imageHeight = image!.size.height
  540. // Calculate the aspect ratio of the image
  541. let aspectRatio = imageWidth / imageHeight
  542. // Calculate the size to display the image while maintaining its aspect ratio
  543. var displayWidth: CGFloat = 0.0
  544. var displayHeight: CGFloat = 0.0
  545. if imageWidth > imageHeight {
  546. // Landscape image
  547. displayWidth = screenWidth
  548. displayHeight = screenWidth / aspectRatio
  549. } else {
  550. // Portrait or square image
  551. displayHeight = screenHeight
  552. displayWidth = screenHeight * aspectRatio
  553. }
  554. return CGSize(width: displayWidth, height: displayHeight)
  555. }
  556. return nil
  557. }
  558. }
  559. class CenteredTitleSubtitleView: UIView {
  560. let titleLabel: UILabel = {
  561. let label = UILabel()
  562. label.textAlignment = .center
  563. label.font = UIFont.boldSystemFont(ofSize: 18)
  564. label.textColor = .white
  565. return label
  566. }()
  567. let subtitleLabel: UILabel = {
  568. let label = UILabel()
  569. label.textAlignment = .center
  570. label.font = UIFont.systemFont(ofSize: 14)
  571. label.textColor = .lightGray
  572. return label
  573. }()
  574. override init(frame: CGRect) {
  575. super.init(frame: frame)
  576. setupSubviews()
  577. }
  578. required init?(coder: NSCoder) {
  579. super.init(coder: coder)
  580. setupSubviews()
  581. }
  582. private func setupSubviews() {
  583. addSubview(titleLabel)
  584. addSubview(subtitleLabel)
  585. // Add any constraints or frames you prefer
  586. // Here's an example using autolayout anchors
  587. titleLabel.translatesAutoresizingMaskIntoConstraints = false
  588. titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
  589. titleLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
  590. subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
  591. subtitleLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
  592. subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true
  593. }
  594. }
  595. class LongPressImageVIew: UILongPressGestureRecognizer {
  596. var imageView = UIImageView()
  597. var index = 0
  598. }