| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- //
- // LabelCell.swift
- // Sirani
- //
- // Created by Hendi on 20/06/23.
- // Copyright © 2026 PT. Mitra Sinerji Teknoindo. All rights reserved.
- //
- import UIKit
- import MaterialComponents.MaterialCards
- protocol LabelCellDelegate: NSObjectProtocol {
- func openLabelDetail(data: Label?)
- }
- class LabelCell: UITableViewCell {
-
- @IBOutlet weak var card: MDCCard!
- @IBOutlet weak var lblNomor: UILabel!
- @IBOutlet weak var lblPemohon: UILabel!
- @IBOutlet weak var lblPerangkat: UILabel!
- @IBOutlet weak var lblMerk: UILabel!
- @IBOutlet weak var lblModel: UILabel!
- @IBOutlet weak var lblBrand: UILabel!
- @IBOutlet weak var lblBerlakuDate: UILabel!
- @IBOutlet weak var lblBerakhirDate: UILabel!
- @IBOutlet weak var lblStatus: UILabel!
- @IBOutlet weak var lblNegara: UILabel!
- var cellDelegate: LabelCellDelegate?
- var dataLabel: Label?
-
- // Modern UI Elements
- private let modernContainer = UIView()
- private let modernBadgeView = UIView()
- private let modernBadgeIcon = UIImageView()
- private let modernNomorLabel = UILabel()
- private let modernCategoryLabel = UILabel()
- private let modernStatusPill = UIView()
- private let modernStatusLabel = UILabel()
-
- private let modernPerangkatLabel = UILabel()
- private let modernCompanyIcon = UIImageView()
- private let modernPemohonLabel = UILabel()
-
- private let modernSpecStack = UIStackView()
- private let modernMerkCard = UIView()
- private let modernMerkTitle = UILabel()
- private let modernMerkVal = UILabel()
-
- private let modernNegaraCard = UIView()
- private let modernNegaraTitle = UILabel()
- private let modernNegaraVal = UILabel()
-
- private let modernValidityCard = UIView()
- private let modernCalendarIcon = UIImageView()
- private let modernValidityLabel = UILabel()
- private let modernDetailLabel = UILabel()
- private let modernChevronIcon = UIImageView()
-
- private var isModernLayoutBuilt = false
-
- override func awakeFromNib() {
- super.awakeFromNib()
-
- self.selectionStyle = .none
- self.backgroundColor = .clear
-
- setupCardVisuals()
- setupModernLayout()
- }
-
- private func setupCardVisuals() {
- guard let card = card else { return }
- card.cornerRadius = 16
- card.setShadowElevation(ShadowElevation(rawValue: 2), for: .normal)
- card.setShadowColor(UIColor.black.withAlphaComponent(0.06), for: .normal)
- card.layer.borderColor = UIColor(red: 228/255, green: 235/255, blue: 245/255, alpha: 1.0).cgColor
- card.layer.borderWidth = 1.0
- card.backgroundColor = .white
- }
-
- private func setupModernLayout() {
- guard let card = card, !isModernLayoutBuilt else { return }
- isModernLayoutBuilt = true
-
- for subview in card.subviews {
- subview.isHidden = true
- }
-
- modernContainer.translatesAutoresizingMaskIntoConstraints = false
- modernContainer.backgroundColor = .clear
- card.addSubview(modernContainer)
-
- NSLayoutConstraint.activate([
- modernContainer.topAnchor.constraint(equalTo: card.topAnchor, constant: 14),
- modernContainer.bottomAnchor.constraint(equalTo: card.bottomAnchor, constant: -14),
- modernContainer.leadingAnchor.constraint(equalTo: card.leadingAnchor, constant: 14),
- modernContainer.trailingAnchor.constraint(equalTo: card.trailingAnchor, constant: -14)
- ])
-
- // 1. Header Bar
- let headerStack = UIStackView()
- headerStack.translatesAutoresizingMaskIntoConstraints = false
- headerStack.axis = .horizontal
- headerStack.alignment = .center
- headerStack.spacing = 10
- modernContainer.addSubview(headerStack)
-
- modernBadgeView.translatesAutoresizingMaskIntoConstraints = false
- modernBadgeView.backgroundColor = UIColor(red: 235/255, green: 242/255, blue: 252/255, alpha: 1.0)
- modernBadgeView.layer.cornerRadius = 8
- modernBadgeView.layer.masksToBounds = true
-
- modernBadgeIcon.translatesAutoresizingMaskIntoConstraints = false
- if #available(iOS 13.0, *) {
- modernBadgeIcon.image = UIImage(systemName: "tag.fill")
- }
- modernBadgeIcon.tintColor = UIColor.siraniPrimaryBlue
- modernBadgeIcon.contentMode = .scaleAspectFit
- modernBadgeView.addSubview(modernBadgeIcon)
-
- NSLayoutConstraint.activate([
- modernBadgeView.widthAnchor.constraint(equalToConstant: 32),
- modernBadgeView.heightAnchor.constraint(equalToConstant: 32),
- modernBadgeIcon.centerXAnchor.constraint(equalTo: modernBadgeView.centerXAnchor),
- modernBadgeIcon.centerYAnchor.constraint(equalTo: modernBadgeView.centerYAnchor),
- modernBadgeIcon.widthAnchor.constraint(equalToConstant: 18),
- modernBadgeIcon.heightAnchor.constraint(equalToConstant: 18)
- ])
- headerStack.addArrangedSubview(modernBadgeView)
-
- let numberStack = UIStackView()
- numberStack.axis = .vertical
- numberStack.spacing = 1
-
- modernCategoryLabel.font = UIFont.systemFont(ofSize: 9, weight: .bold)
- modernCategoryLabel.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0)
- modernCategoryLabel.text = "NOMOR SERTIFIKAT LABEL"
- numberStack.addArrangedSubview(modernCategoryLabel)
-
- modernNomorLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold)
- modernNomorLabel.textColor = UIColor.siraniPrimaryBlue
- modernNomorLabel.numberOfLines = 1
- modernNomorLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
- modernNomorLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
- numberStack.addArrangedSubview(modernNomorLabel)
-
- headerStack.addArrangedSubview(numberStack)
-
- // Status Pill
- modernStatusPill.translatesAutoresizingMaskIntoConstraints = false
- modernStatusPill.layer.cornerRadius = 6
- modernStatusPill.layer.masksToBounds = true
- modernStatusPill.backgroundColor = UIColor(red: 230/255, green: 244/255, blue: 234/255, alpha: 1.0)
-
- modernStatusLabel.translatesAutoresizingMaskIntoConstraints = false
- modernStatusLabel.font = UIFont.systemFont(ofSize: 10, weight: .bold)
- modernStatusLabel.textColor = UIColor(red: 19/255, green: 115/255, blue: 51/255, alpha: 1.0)
- modernStatusLabel.textAlignment = .center
- modernStatusPill.addSubview(modernStatusLabel)
-
- NSLayoutConstraint.activate([
- modernStatusLabel.topAnchor.constraint(equalTo: modernStatusPill.topAnchor, constant: 4),
- modernStatusLabel.bottomAnchor.constraint(equalTo: modernStatusPill.bottomAnchor, constant: -4),
- modernStatusLabel.leadingAnchor.constraint(equalTo: modernStatusPill.leadingAnchor, constant: 8),
- modernStatusLabel.trailingAnchor.constraint(equalTo: modernStatusPill.trailingAnchor, constant: -8)
- ])
- headerStack.addArrangedSubview(modernStatusPill)
-
- // 2. Divider
- let divider = UIView()
- divider.translatesAutoresizingMaskIntoConstraints = false
- divider.backgroundColor = UIColor(red: 240/255, green: 244/255, blue: 250/255, alpha: 1.0)
- modernContainer.addSubview(divider)
-
- // 3. Equipment Name
- modernPerangkatLabel.translatesAutoresizingMaskIntoConstraints = false
- modernPerangkatLabel.font = UIFont.systemFont(ofSize: 15, weight: .bold)
- modernPerangkatLabel.textColor = UIColor(red: 26/255, green: 29/255, blue: 38/255, alpha: 1.0)
- modernPerangkatLabel.numberOfLines = 2
- modernContainer.addSubview(modernPerangkatLabel)
-
- // 4. Company Row
- let companyStack = UIStackView()
- companyStack.translatesAutoresizingMaskIntoConstraints = false
- companyStack.axis = .horizontal
- companyStack.spacing = 6
- companyStack.alignment = .center
-
- if #available(iOS 13.0, *) {
- modernCompanyIcon.image = UIImage(systemName: "building.2.fill")
- }
- modernCompanyIcon.tintColor = UIColor(red: 120/255, green: 135/255, blue: 155/255, alpha: 1.0)
- modernCompanyIcon.contentMode = .scaleAspectFit
- modernCompanyIcon.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- modernCompanyIcon.widthAnchor.constraint(equalToConstant: 14),
- modernCompanyIcon.heightAnchor.constraint(equalToConstant: 14)
- ])
- companyStack.addArrangedSubview(modernCompanyIcon)
-
- modernPemohonLabel.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
- modernPemohonLabel.textColor = UIColor(red: 90/255, green: 105/255, blue: 125/255, alpha: 1.0)
- modernPemohonLabel.numberOfLines = 1
- companyStack.addArrangedSubview(modernPemohonLabel)
- modernContainer.addSubview(companyStack)
-
- // 5. Spec Mini Cards
- modernSpecStack.translatesAutoresizingMaskIntoConstraints = false
- modernSpecStack.axis = .horizontal
- modernSpecStack.distribution = .fillEqually
- modernSpecStack.spacing = 8
- modernContainer.addSubview(modernSpecStack)
-
- // Merk Card
- modernMerkCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0)
- modernMerkCard.layer.cornerRadius = 8
- modernMerkCard.layer.borderWidth = 1
- modernMerkCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor
-
- let merkInnerStack = UIStackView()
- merkInnerStack.translatesAutoresizingMaskIntoConstraints = false
- merkInnerStack.axis = .vertical
- merkInnerStack.spacing = 2
- modernMerkCard.addSubview(merkInnerStack)
-
- modernMerkTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold)
- modernMerkTitle.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0)
- modernMerkTitle.text = "MERK & MODEL"
- merkInnerStack.addArrangedSubview(modernMerkTitle)
-
- modernMerkVal.font = UIFont.systemFont(ofSize: 11, weight: .semibold)
- modernMerkVal.textColor = UIColor(red: 40/255, green: 50/255, blue: 65/255, alpha: 1.0)
- modernMerkVal.numberOfLines = 1
- merkInnerStack.addArrangedSubview(modernMerkVal)
-
- NSLayoutConstraint.activate([
- merkInnerStack.topAnchor.constraint(equalTo: modernMerkCard.topAnchor, constant: 6),
- merkInnerStack.bottomAnchor.constraint(equalTo: modernMerkCard.bottomAnchor, constant: -6),
- merkInnerStack.leadingAnchor.constraint(equalTo: modernMerkCard.leadingAnchor, constant: 8),
- merkInnerStack.trailingAnchor.constraint(equalTo: modernMerkCard.trailingAnchor, constant: -8)
- ])
- modernSpecStack.addArrangedSubview(modernMerkCard)
-
- // Negara Card
- modernNegaraCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0)
- modernNegaraCard.layer.cornerRadius = 8
- modernNegaraCard.layer.borderWidth = 1
- modernNegaraCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor
-
- let negaraInnerStack = UIStackView()
- negaraInnerStack.translatesAutoresizingMaskIntoConstraints = false
- negaraInnerStack.axis = .vertical
- negaraInnerStack.spacing = 2
- modernNegaraCard.addSubview(negaraInnerStack)
-
- modernNegaraTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold)
- modernNegaraTitle.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0)
- modernNegaraTitle.text = "NEGARA ASAL"
- negaraInnerStack.addArrangedSubview(modernNegaraTitle)
-
- modernNegaraVal.font = UIFont.systemFont(ofSize: 11, weight: .semibold)
- modernNegaraVal.textColor = UIColor(red: 40/255, green: 50/255, blue: 65/255, alpha: 1.0)
- modernNegaraVal.numberOfLines = 1
- negaraInnerStack.addArrangedSubview(modernNegaraVal)
-
- NSLayoutConstraint.activate([
- negaraInnerStack.topAnchor.constraint(equalTo: modernNegaraCard.topAnchor, constant: 6),
- negaraInnerStack.bottomAnchor.constraint(equalTo: modernNegaraCard.bottomAnchor, constant: -6),
- negaraInnerStack.leadingAnchor.constraint(equalTo: modernNegaraCard.leadingAnchor, constant: 8),
- negaraInnerStack.trailingAnchor.constraint(equalTo: modernNegaraCard.trailingAnchor, constant: -8)
- ])
- modernSpecStack.addArrangedSubview(modernNegaraCard)
-
- // 6. Validity Bar
- modernValidityCard.translatesAutoresizingMaskIntoConstraints = false
- modernValidityCard.backgroundColor = UIColor(red: 244/255, green: 248/255, blue: 254/255, alpha: 1.0)
- modernValidityCard.layer.cornerRadius = 8
- modernContainer.addSubview(modernValidityCard)
-
- let validityStack = UIStackView()
- validityStack.translatesAutoresizingMaskIntoConstraints = false
- validityStack.axis = .horizontal
- validityStack.alignment = .center
- validityStack.spacing = 6
- modernValidityCard.addSubview(validityStack)
-
- if #available(iOS 13.0, *) {
- modernCalendarIcon.image = UIImage(systemName: "calendar")
- }
- modernCalendarIcon.tintColor = UIColor.siraniPrimaryBlue
- modernCalendarIcon.contentMode = .scaleAspectFit
- modernCalendarIcon.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- modernCalendarIcon.widthAnchor.constraint(equalToConstant: 13),
- modernCalendarIcon.heightAnchor.constraint(equalToConstant: 13)
- ])
- validityStack.addArrangedSubview(modernCalendarIcon)
-
- modernValidityLabel.font = UIFont.systemFont(ofSize: 11, weight: .medium)
- modernValidityLabel.textColor = UIColor(red: 50/255, green: 70/255, blue: 95/255, alpha: 1.0)
- modernValidityLabel.numberOfLines = 1
- validityStack.addArrangedSubview(modernValidityLabel)
-
- let spacer = UIView()
- spacer.setContentHuggingPriority(.defaultLow, for: .horizontal)
- validityStack.addArrangedSubview(spacer)
-
- modernDetailLabel.font = UIFont.systemFont(ofSize: 11, weight: .bold)
- modernDetailLabel.textColor = UIColor.siraniPrimaryBlue
- modernDetailLabel.text = "Detail"
- validityStack.addArrangedSubview(modernDetailLabel)
-
- if #available(iOS 13.0, *) {
- modernChevronIcon.image = UIImage(systemName: "chevron.right")
- }
- modernChevronIcon.tintColor = UIColor.siraniPrimaryBlue
- modernChevronIcon.contentMode = .scaleAspectFit
- modernChevronIcon.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- modernChevronIcon.widthAnchor.constraint(equalToConstant: 10),
- modernChevronIcon.heightAnchor.constraint(equalToConstant: 10)
- ])
- validityStack.addArrangedSubview(modernChevronIcon)
-
- NSLayoutConstraint.activate([
- validityStack.topAnchor.constraint(equalTo: modernValidityCard.topAnchor, constant: 6),
- validityStack.bottomAnchor.constraint(equalTo: modernValidityCard.bottomAnchor, constant: -6),
- validityStack.leadingAnchor.constraint(equalTo: modernValidityCard.leadingAnchor, constant: 10),
- validityStack.trailingAnchor.constraint(equalTo: modernValidityCard.trailingAnchor, constant: -10)
- ])
-
- NSLayoutConstraint.activate([
- headerStack.topAnchor.constraint(equalTo: modernContainer.topAnchor),
- headerStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
- headerStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
-
- divider.topAnchor.constraint(equalTo: headerStack.bottomAnchor, constant: 10),
- divider.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
- divider.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
- divider.heightAnchor.constraint(equalToConstant: 1),
-
- modernPerangkatLabel.topAnchor.constraint(equalTo: divider.bottomAnchor, constant: 10),
- modernPerangkatLabel.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
- modernPerangkatLabel.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
-
- companyStack.topAnchor.constraint(equalTo: modernPerangkatLabel.bottomAnchor, constant: 6),
- companyStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
- companyStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
-
- modernSpecStack.topAnchor.constraint(equalTo: companyStack.bottomAnchor, constant: 10),
- modernSpecStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
- modernSpecStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
-
- modernValidityCard.topAnchor.constraint(equalTo: modernSpecStack.bottomAnchor, constant: 10),
- modernValidityCard.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor),
- modernValidityCard.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor),
- modernValidityCard.bottomAnchor.constraint(equalTo: modernContainer.bottomAnchor)
- ])
- }
-
- func updateViews(labelData: Label) {
- setupCardVisuals()
- setupModernLayout()
-
- card.isInteractable = true
- let gesture = UITapGestureRecognizer(target: self, action: #selector(self.onItemTap))
- card.addGestureRecognizer(gesture)
-
- modernNomorLabel.text = labelData.nomor.isEmpty ? "-" : labelData.nomor
-
- let statusStr = labelData.statusBerlaku.trimmingCharacters(in: .whitespacesAndNewlines)
- let displayStatus = statusStr.isEmpty ? "TERBIT" : statusStr.uppercased()
- modernStatusLabel.text = displayStatus
-
- if displayStatus.contains("CABUT") || displayStatus.contains("TIDAK") {
- modernStatusPill.backgroundColor = UIColor(red: 254/255, green: 242/255, blue: 242/255, alpha: 1.0)
- modernStatusLabel.textColor = UIColor(red: 220/255, green: 38/255, blue: 38/255, alpha: 1.0)
- } else if displayStatus.contains("REVISI") || displayStatus.contains("PROSES") {
- modernStatusPill.backgroundColor = UIColor(red: 254/255, green: 249/255, blue: 235/255, alpha: 1.0)
- modernStatusLabel.textColor = UIColor(red: 180/255, green: 83/255, blue: 9/255, alpha: 1.0)
- } else {
- modernStatusPill.backgroundColor = UIColor(red: 230/255, green: 244/255, blue: 234/255, alpha: 1.0)
- modernStatusLabel.textColor = UIColor(red: 19/255, green: 115/255, blue: 51/255, alpha: 1.0)
- }
-
- modernPerangkatLabel.text = labelData.eqp_name.isEmpty ? "-" : labelData.eqp_name
- modernPemohonLabel.text = labelData.cust_name.isEmpty ? "-" : labelData.cust_name
-
- var mm = labelData.merk
- if !labelData.model.isEmpty && labelData.model != "null" {
- mm = mm.isEmpty ? labelData.model : "\(mm) • \(labelData.model)"
- }
- modernMerkVal.text = mm.isEmpty ? "-" : mm
-
- let negara = labelData.negara.trimmingCharacters(in: .whitespacesAndNewlines)
- modernNegaraVal.text = (negara.isEmpty || negara == "null") ? "-" : negara
-
- let tglBerlaku = CommonHelper.formatDate(from: labelData.lic_date)
- let tglBerakhir = CommonHelper.formatDate(from: labelData.exp_date)
-
- if tglBerlaku != "-" && tglBerakhir != "-" {
- modernValidityLabel.text = "Berlaku: \(tglBerlaku) s/d \(tglBerakhir)"
- } else if tglBerlaku != "-" {
- modernValidityLabel.text = "Berlaku: \(tglBerlaku)"
- } else {
- modernValidityLabel.text = "Masa Berlaku: -"
- }
-
- self.dataLabel = labelData
- }
-
- @objc func onItemTap(sender: UITapGestureRecognizer) {
- cellDelegate?.openLabelDetail(data: dataLabel)
- }
- }
|