AplikasiCell.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. //
  2. // AplikasiCell.swift
  3. // Sirani
  4. //
  5. // Created by Hendi on 21/06/23.
  6. // Copyright © 2026 PT. Mitra Sinerji Teknoindo. All rights reserved.
  7. //
  8. import UIKit
  9. import MaterialComponents.MaterialCards
  10. import SkeletonView
  11. protocol AplikasiCellDelegate: NSObjectProtocol {
  12. func openAplikasiDetail(data: Aplikasi?)
  13. }
  14. class AplikasiCell: UITableViewCell {
  15. @IBOutlet weak var card: MDCCard!
  16. @IBOutlet weak var lblIdIzin: UILabel!
  17. @IBOutlet weak var lblAplId: UILabel!
  18. @IBOutlet weak var lblResiNo: UILabel!
  19. @IBOutlet weak var lblResiDate: UILabel!
  20. @IBOutlet weak var lblCustName: UILabel!
  21. @IBOutlet weak var lblEqpName: UILabel!
  22. @IBOutlet weak var lblMerk: UILabel!
  23. @IBOutlet weak var lblModel: UILabel!
  24. @IBOutlet weak var lblBrand: UILabel!
  25. @IBOutlet weak var lblDisposisi: UILabel!
  26. @IBOutlet weak var lblStatusStr: UILabel!
  27. @IBOutlet weak var statusTop: NSLayoutConstraint!
  28. @IBOutlet weak var disposisiTitle: UILabel!
  29. var cellDelegate: AplikasiCellDelegate?
  30. var dataAplikasi: Aplikasi?
  31. // Modern Programmatic Subviews
  32. private let modernContainer = UIView()
  33. private let modernBadgeView = UIView()
  34. private let modernBadgeIcon = UIImageView()
  35. private let modernAplIdLabel = UILabel()
  36. private let modernIdIzinLabel = UILabel()
  37. private let modernCategoryLabel = UILabel()
  38. private let modernStatusPill = UIView()
  39. private let modernStatusLabel = UILabel()
  40. private let modernEqpLabel = UILabel()
  41. private let modernCompanyIcon = UIImageView()
  42. private let modernCustLabel = UILabel()
  43. private let modernSpecStack = UIStackView()
  44. private let modernMerkCard = UIView()
  45. private let modernMerkTitle = UILabel()
  46. private let modernMerkVal = UILabel()
  47. private let modernResiCard = UIView()
  48. private let modernResiTitle = UILabel()
  49. private let modernResiVal = UILabel()
  50. private let modernDisposisiCard = UIView()
  51. private let modernDisposisiIcon = UIImageView()
  52. private let modernDisposisiLabel = UILabel()
  53. private let modernDetailLabel = UILabel()
  54. private let modernChevronIcon = UIImageView()
  55. private var isModernLayoutBuilt = false
  56. override func awakeFromNib() {
  57. super.awakeFromNib()
  58. self.selectionStyle = .none
  59. self.backgroundColor = .clear
  60. setupCardVisuals()
  61. setupModernLayout()
  62. }
  63. private func setupCardVisuals() {
  64. guard let card = card else { return }
  65. card.cornerRadius = 16
  66. card.setShadowElevation(ShadowElevation(rawValue: 2), for: .normal)
  67. card.setShadowColor(UIColor.black.withAlphaComponent(0.06), for: .normal)
  68. card.layer.borderColor = UIColor(red: 228/255, green: 235/255, blue: 245/255, alpha: 1.0).cgColor
  69. card.layer.borderWidth = 1.0
  70. card.backgroundColor = .white
  71. }
  72. private func setupModernLayout() {
  73. guard let card = card, !isModernLayoutBuilt else { return }
  74. isModernLayoutBuilt = true
  75. for subview in card.subviews {
  76. subview.isHidden = true
  77. }
  78. modernContainer.translatesAutoresizingMaskIntoConstraints = false
  79. modernContainer.backgroundColor = .clear
  80. card.addSubview(modernContainer)
  81. NSLayoutConstraint.activate([
  82. modernContainer.topAnchor.constraint(equalTo: card.topAnchor, constant: 14),
  83. modernContainer.bottomAnchor.constraint(equalTo: card.bottomAnchor, constant: -14),
  84. modernContainer.leadingAnchor.constraint(equalTo: card.leadingAnchor, constant: 14),
  85. modernContainer.trailingAnchor.constraint(equalTo: card.trailingAnchor, constant: -14)
  86. ])
  87. // 1. Header Bar
  88. let headerStack = UIStackView()
  89. headerStack.translatesAutoresizingMaskIntoConstraints = false
  90. headerStack.axis = .horizontal
  91. headerStack.alignment = .center
  92. headerStack.spacing = 10
  93. modernContainer.addSubview(headerStack)
  94. modernBadgeView.translatesAutoresizingMaskIntoConstraints = false
  95. modernBadgeView.backgroundColor = UIColor(red: 235/255, green: 242/255, blue: 252/255, alpha: 1.0)
  96. modernBadgeView.layer.cornerRadius = 8
  97. modernBadgeView.layer.masksToBounds = true
  98. modernBadgeIcon.translatesAutoresizingMaskIntoConstraints = false
  99. if #available(iOS 13.0, *) {
  100. modernBadgeIcon.image = UIImage(systemName: "app.badge.fill")
  101. }
  102. modernBadgeIcon.tintColor = UIColor.siraniPrimaryBlue
  103. modernBadgeIcon.contentMode = .scaleAspectFit
  104. modernBadgeView.addSubview(modernBadgeIcon)
  105. NSLayoutConstraint.activate([
  106. modernBadgeView.widthAnchor.constraint(equalToConstant: 32),
  107. modernBadgeView.heightAnchor.constraint(equalToConstant: 32),
  108. modernBadgeIcon.centerXAnchor.constraint(equalTo: modernBadgeView.centerXAnchor),
  109. modernBadgeIcon.centerYAnchor.constraint(equalTo: modernBadgeView.centerYAnchor),
  110. modernBadgeIcon.widthAnchor.constraint(equalToConstant: 18),
  111. modernBadgeIcon.heightAnchor.constraint(equalToConstant: 18)
  112. ])
  113. headerStack.addArrangedSubview(modernBadgeView)
  114. let idStack = UIStackView()
  115. idStack.axis = .vertical
  116. idStack.spacing = 2
  117. modernAplIdLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold)
  118. modernAplIdLabel.textColor = UIColor.siraniPrimaryBlue
  119. modernAplIdLabel.numberOfLines = 1
  120. modernAplIdLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
  121. modernAplIdLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
  122. idStack.addArrangedSubview(modernAplIdLabel)
  123. modernIdIzinLabel.font = UIFont.systemFont(ofSize: 11, weight: .semibold)
  124. modernIdIzinLabel.textColor = UIColor(red: 113/255, green: 128/255, blue: 150/255, alpha: 1.0)
  125. modernIdIzinLabel.numberOfLines = 1
  126. modernIdIzinLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
  127. modernIdIzinLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
  128. idStack.addArrangedSubview(modernIdIzinLabel)
  129. headerStack.addArrangedSubview(idStack)
  130. // Status Pill
  131. modernStatusPill.translatesAutoresizingMaskIntoConstraints = false
  132. modernStatusPill.layer.cornerRadius = 6
  133. modernStatusPill.layer.masksToBounds = true
  134. modernStatusPill.backgroundColor = UIColor(red: 230/255, green: 244/255, blue: 234/255, alpha: 1.0)
  135. modernStatusLabel.translatesAutoresizingMaskIntoConstraints = false
  136. modernStatusLabel.font = UIFont.systemFont(ofSize: 10, weight: .bold)
  137. modernStatusLabel.textColor = UIColor(red: 19/255, green: 115/255, blue: 51/255, alpha: 1.0)
  138. modernStatusLabel.textAlignment = .center
  139. modernStatusPill.addSubview(modernStatusLabel)
  140. NSLayoutConstraint.activate([
  141. modernStatusLabel.topAnchor.constraint(equalTo: modernStatusPill.topAnchor, constant: 4),
  142. modernStatusLabel.bottomAnchor.constraint(equalTo: modernStatusPill.bottomAnchor, constant: -4),
  143. modernStatusLabel.leadingAnchor.constraint(equalTo: modernStatusPill.leadingAnchor, constant: 8),
  144. modernStatusLabel.trailingAnchor.constraint(equalTo: modernStatusPill.trailingAnchor, constant: -8)
  145. ])
  146. headerStack.addArrangedSubview(modernStatusPill)
  147. // 2. Divider
  148. let divider = UIView()
  149. divider.translatesAutoresizingMaskIntoConstraints = false
  150. divider.backgroundColor = UIColor(red: 240/255, green: 244/255, blue: 250/255, alpha: 1.0)
  151. modernContainer.addSubview(divider)
  152. // 3. Equipment Name
  153. modernEqpLabel.translatesAutoresizingMaskIntoConstraints = false
  154. modernEqpLabel.font = UIFont.systemFont(ofSize: 15, weight: .bold)
  155. modernEqpLabel.textColor = UIColor(red: 26/255, green: 29/255, blue: 38/255, alpha: 1.0)
  156. modernEqpLabel.numberOfLines = 2
  157. modernContainer.addSubview(modernEqpLabel)
  158. // 4. Company Row
  159. let companyStack = UIStackView()
  160. companyStack.translatesAutoresizingMaskIntoConstraints = false
  161. companyStack.axis = .horizontal
  162. companyStack.spacing = 6
  163. companyStack.alignment = .center
  164. if #available(iOS 13.0, *) {
  165. modernCompanyIcon.image = UIImage(systemName: "building.2.fill")
  166. }
  167. modernCompanyIcon.tintColor = UIColor(red: 120/255, green: 135/255, blue: 155/255, alpha: 1.0)
  168. modernCompanyIcon.contentMode = .scaleAspectFit
  169. modernCompanyIcon.translatesAutoresizingMaskIntoConstraints = false
  170. NSLayoutConstraint.activate([
  171. modernCompanyIcon.widthAnchor.constraint(equalToConstant: 14),
  172. modernCompanyIcon.heightAnchor.constraint(equalToConstant: 14)
  173. ])
  174. companyStack.addArrangedSubview(modernCompanyIcon)
  175. modernCustLabel.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
  176. modernCustLabel.textColor = UIColor(red: 90/255, green: 105/255, blue: 125/255, alpha: 1.0)
  177. modernCustLabel.numberOfLines = 1
  178. companyStack.addArrangedSubview(modernCustLabel)
  179. modernContainer.addSubview(companyStack)
  180. // 5. Spec Mini Cards
  181. modernSpecStack.translatesAutoresizingMaskIntoConstraints = false
  182. modernSpecStack.axis = .horizontal
  183. modernSpecStack.distribution = .fillEqually
  184. modernSpecStack.spacing = 8
  185. modernContainer.addSubview(modernSpecStack)
  186. // Merk Card
  187. modernMerkCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0)
  188. modernMerkCard.layer.cornerRadius = 8
  189. modernMerkCard.layer.borderWidth = 1
  190. modernMerkCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor
  191. let merkInnerStack = UIStackView()
  192. merkInnerStack.translatesAutoresizingMaskIntoConstraints = false
  193. merkInnerStack.axis = .vertical
  194. merkInnerStack.spacing = 2
  195. modernMerkCard.addSubview(merkInnerStack)
  196. modernMerkTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold)
  197. modernMerkTitle.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0)
  198. modernMerkTitle.text = "MERK & MODEL"
  199. merkInnerStack.addArrangedSubview(modernMerkTitle)
  200. modernMerkVal.font = UIFont.systemFont(ofSize: 11, weight: .semibold)
  201. modernMerkVal.textColor = UIColor(red: 40/255, green: 50/255, blue: 65/255, alpha: 1.0)
  202. modernMerkVal.numberOfLines = 1
  203. merkInnerStack.addArrangedSubview(modernMerkVal)
  204. NSLayoutConstraint.activate([
  205. merkInnerStack.topAnchor.constraint(equalTo: modernMerkCard.topAnchor, constant: 6),
  206. merkInnerStack.bottomAnchor.constraint(equalTo: modernMerkCard.bottomAnchor, constant: -6),
  207. merkInnerStack.leadingAnchor.constraint(equalTo: modernMerkCard.leadingAnchor, constant: 8),
  208. merkInnerStack.trailingAnchor.constraint(equalTo: modernMerkCard.trailingAnchor, constant: -8)
  209. ])
  210. modernSpecStack.addArrangedSubview(modernMerkCard)
  211. // Resi Card
  212. modernResiCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0)
  213. modernResiCard.layer.cornerRadius = 8
  214. modernResiCard.layer.borderWidth = 1
  215. modernResiCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor
  216. let resiInnerStack = UIStackView()
  217. resiInnerStack.translatesAutoresizingMaskIntoConstraints = false
  218. resiInnerStack.axis = .vertical
  219. resiInnerStack.spacing = 2
  220. modernResiCard.addSubview(resiInnerStack)
  221. modernResiTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold)
  222. modernResiTitle.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0)
  223. modernResiTitle.text = "NO. RESI"
  224. resiInnerStack.addArrangedSubview(modernResiTitle)
  225. modernResiVal.font = UIFont.systemFont(ofSize: 11, weight: .semibold)
  226. modernResiVal.textColor = UIColor(red: 40/255, green: 50/255, blue: 65/255, alpha: 1.0)
  227. modernResiVal.numberOfLines = 1
  228. resiInnerStack.addArrangedSubview(modernResiVal)
  229. NSLayoutConstraint.activate([
  230. resiInnerStack.topAnchor.constraint(equalTo: modernResiCard.topAnchor, constant: 6),
  231. resiInnerStack.bottomAnchor.constraint(equalTo: modernResiCard.bottomAnchor, constant: -6),
  232. resiInnerStack.leadingAnchor.constraint(equalTo: modernResiCard.leadingAnchor, constant: 8),
  233. resiInnerStack.trailingAnchor.constraint(equalTo: modernResiCard.trailingAnchor, constant: -8)
  234. ])
  235. modernSpecStack.addArrangedSubview(modernResiCard)
  236. // 6. Disposisi / Bottom Footer
  237. modernDisposisiCard.translatesAutoresizingMaskIntoConstraints = false
  238. modernDisposisiCard.backgroundColor = UIColor(red: 244/255, green: 248/255, blue: 254/255, alpha: 1.0)
  239. modernDisposisiCard.layer.cornerRadius = 8
  240. modernContainer.addSubview(modernDisposisiCard)
  241. let disposisiStack = UIStackView()
  242. disposisiStack.translatesAutoresizingMaskIntoConstraints = false
  243. disposisiStack.axis = .horizontal
  244. disposisiStack.alignment = .center
  245. disposisiStack.spacing = 6
  246. modernDisposisiCard.addSubview(disposisiStack)
  247. if #available(iOS 13.0, *) {
  248. modernDisposisiIcon.image = UIImage(systemName: "arrow.triangle.branch")
  249. }
  250. modernDisposisiIcon.tintColor = UIColor.siraniPrimaryBlue
  251. modernDisposisiIcon.contentMode = .scaleAspectFit
  252. modernDisposisiIcon.translatesAutoresizingMaskIntoConstraints = false
  253. NSLayoutConstraint.activate([
  254. modernDisposisiIcon.widthAnchor.constraint(equalToConstant: 13),
  255. modernDisposisiIcon.heightAnchor.constraint(equalToConstant: 13)
  256. ])
  257. disposisiStack.addArrangedSubview(modernDisposisiIcon)
  258. modernDisposisiLabel.font = UIFont.systemFont(ofSize: 11, weight: .medium)
  259. modernDisposisiLabel.textColor = UIColor(red: 50/255, green: 70/255, blue: 95/255, alpha: 1.0)
  260. modernDisposisiLabel.numberOfLines = 1
  261. disposisiStack.addArrangedSubview(modernDisposisiLabel)
  262. let spacer = UIView()
  263. spacer.setContentHuggingPriority(.defaultLow, for: .horizontal)
  264. disposisiStack.addArrangedSubview(spacer)
  265. modernDetailLabel.font = UIFont.systemFont(ofSize: 11, weight: .bold)
  266. modernDetailLabel.textColor = UIColor.siraniPrimaryBlue
  267. modernDetailLabel.text = "Detail"
  268. disposisiStack.addArrangedSubview(modernDetailLabel)
  269. if #available(iOS 13.0, *) {
  270. modernChevronIcon.image = UIImage(systemName: "chevron.right")
  271. }
  272. modernChevronIcon.tintColor = UIColor.siraniPrimaryBlue
  273. modernChevronIcon.contentMode = .scaleAspectFit
  274. modernChevronIcon.translatesAutoresizingMaskIntoConstraints = false
  275. NSLayoutConstraint.activate([
  276. modernChevronIcon.widthAnchor.constraint(equalToConstant: 10),
  277. modernChevronIcon.heightAnchor.constraint(equalToConstant: 10)
  278. ])
  279. disposisiStack.addArrangedSubview(modernChevronIcon)
  280. NSLayoutConstraint.activate([
  281. disposisiStack.topAnchor.constraint(equalTo: modernDisposisiCard.topAnchor, constant: 6),
  282. disposisiStack.bottomAnchor.constraint(equalTo: modernDisposisiCard.bottomAnchor, constant: -6),
  283. disposisiStack.leadingAnchor.constraint(equalTo: modernDisposisiCard.leadingAnchor, constant: 10),
  284. disposisiStack.trailingAnchor.constraint(equalTo: modernDisposisiCard.trailingAnchor, constant: -10)
  285. ])
  286. NSLayoutConstraint.activate([
  287. headerStack.topAnchor.constraint(equalTo: modernContainer.topAnchor),
  288. headerStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
  289. headerStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
  290. divider.topAnchor.constraint(equalTo: headerStack.bottomAnchor, constant: 10),
  291. divider.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
  292. divider.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
  293. divider.heightAnchor.constraint(equalToConstant: 1),
  294. modernEqpLabel.topAnchor.constraint(equalTo: divider.bottomAnchor, constant: 10),
  295. modernEqpLabel.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
  296. modernEqpLabel.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
  297. companyStack.topAnchor.constraint(equalTo: modernEqpLabel.bottomAnchor, constant: 6),
  298. companyStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
  299. companyStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
  300. modernSpecStack.topAnchor.constraint(equalTo: companyStack.bottomAnchor, constant: 10),
  301. modernSpecStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
  302. modernSpecStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
  303. modernDisposisiCard.topAnchor.constraint(equalTo: modernSpecStack.bottomAnchor, constant: 10),
  304. modernDisposisiCard.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
  305. modernDisposisiCard.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
  306. modernDisposisiCard.bottomAnchor.constraint(equalTo: modernContainer.bottomAnchor)
  307. ])
  308. }
  309. func updateViews(aplData: Aplikasi) {
  310. setupCardVisuals()
  311. setupModernLayout()
  312. card.isInteractable = true
  313. card.isUserInteractionEnabled = true
  314. modernContainer.isUserInteractionEnabled = true
  315. modernDisposisiCard.isUserInteractionEnabled = true
  316. if let gestures = card.gestureRecognizers {
  317. for g in gestures { card.removeGestureRecognizer(g) }
  318. }
  319. let gesture = UITapGestureRecognizer(target: self, action: #selector(self.onItemTap))
  320. card.addGestureRecognizer(gesture)
  321. if let disposisiGestures = modernDisposisiCard.gestureRecognizers {
  322. for g in disposisiGestures { modernDisposisiCard.removeGestureRecognizer(g) }
  323. }
  324. let disposisiGesture = UITapGestureRecognizer(target: self, action: #selector(self.onItemTap))
  325. modernDisposisiCard.addGestureRecognizer(disposisiGesture)
  326. modernAplIdLabel.text = "APL ID: \(aplData.apl_id)"
  327. lblAplId?.text = "\(aplData.apl_id)"
  328. let idIzinStr = aplData.id_izin.isEmpty ? "-" : aplData.id_izin
  329. modernIdIzinLabel.text = "ID Izin: \(idIzinStr)"
  330. lblIdIzin?.text = idIzinStr
  331. let statusStr = aplData.StatusStr.trimmingCharacters(in: .whitespacesAndNewlines)
  332. modernStatusLabel.text = statusStr.isEmpty ? "PROSES" : statusStr.uppercased()
  333. if let statusColor = UIColor(hexString: aplData.StatusBgColor) {
  334. modernStatusPill.backgroundColor = statusColor.withAlphaComponent(0.15)
  335. modernStatusLabel.textColor = statusColor
  336. } else {
  337. modernStatusPill.backgroundColor = UIColor(red: 235/255, green: 242/255, blue: 252/255, alpha: 1.0)
  338. modernStatusLabel.textColor = UIColor.siraniPrimaryBlue
  339. }
  340. modernEqpLabel.text = aplData.eqp_name.isEmpty ? "-" : aplData.eqp_name
  341. modernCustLabel.text = aplData.cust_name.isEmpty ? "-" : aplData.cust_name
  342. var mm = aplData.merk
  343. if !aplData.model.isEmpty && aplData.model != "null" {
  344. mm = mm.isEmpty ? aplData.model : "\(mm) • \(aplData.model)"
  345. }
  346. modernMerkVal.text = mm.isEmpty ? "-" : mm
  347. modernResiVal.text = aplData.resi_no.isEmpty ? "-" : aplData.resi_no
  348. let roleId = UserState.instance.getRoleId()
  349. if roleId == "17" || aplData.disposisi.isEmpty {
  350. let resiDate = CommonHelper.formatDate(from: aplData.resi_date)
  351. modernDisposisiLabel.text = resiDate == "-" ? "Permohonan Layanan DJID" : "Tanggal Resi: \(resiDate)"
  352. } else {
  353. modernDisposisiLabel.text = "Disposisi: \(aplData.disposisi)"
  354. }
  355. self.dataAplikasi = aplData
  356. }
  357. @objc func onItemTap(sender: UITapGestureRecognizer) {
  358. cellDelegate?.openAplikasiDetail(data: dataAplikasi)
  359. }
  360. }