// // SertifikatDaftarPencabutanCell.swift // Sirani // // Created by Anhar Solehudin on 26/04/19. // Copyright © 2019 Anhar Solehudin. All rights reserved. // import UIKit import MaterialComponents.MaterialCards class SertifikatDaftarPencabutanCell: UITableViewCell { @IBOutlet weak var card: MDCCard! @IBOutlet weak var lblAplikasiId: UILabel! @IBOutlet weak var lblNo: UILabel! @IBOutlet weak var lblExpDate: UILabel! @IBOutlet weak var lblCustName: UILabel! @IBOutlet weak var lblEqpName: UILabel! @IBOutlet weak var lblModels: UILabel! @IBOutlet weak var lblKeterangan: UILabel! @IBOutlet weak var cbKasi: UIImageView! @IBOutlet weak var cbKasub: UIImageView! @IBOutlet weak var cbDirektur: UIImageView! // Modern Programmatic 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 modernModelsCard = UIView() private let modernModelsTitle = UILabel() private let modernModelsVal = UILabel() private let modernAlasanCard = UIView() private let modernAlasanIcon = UIImageView() private let modernAlasanLabel = UILabel() private let modernApprovalStack = UIStackView() private let modernKasiBadge = UIView() private let modernKasiLabel = UILabel() private let modernKasubBadge = UIView() private let modernKasubLabel = UILabel() private let modernDirutBadge = UIView() private let modernDirutLabel = UILabel() private let modernValidityCard = UIView() private let modernCalendarIcon = UIImageView() private let modernValidityLabel = UILabel() private let modernAplIdLabel = UILabel() 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: 254/255, green: 226/255, blue: 226/255, alpha: 1.0) modernBadgeView.layer.cornerRadius = 8 modernBadgeView.layer.masksToBounds = true modernBadgeIcon.translatesAutoresizingMaskIntoConstraints = false if #available(iOS 13.0, *) { modernBadgeIcon.image = UIImage(systemName: "exclamationmark.octagon.fill") } modernBadgeIcon.tintColor = UIColor(red: 185/255, green: 28/255, blue: 28/255, alpha: 1.0) modernBadgeIcon.contentMode = .scaleAspectFit modernBadgeView.addSubview(modernBadgeIcon) let titleStack = UIStackView() titleStack.translatesAutoresizingMaskIntoConstraints = false titleStack.axis = .vertical titleStack.spacing = 2 modernCategoryLabel.translatesAutoresizingMaskIntoConstraints = false modernCategoryLabel.font = UIFont.systemFont(ofSize: 10, weight: .bold) modernCategoryLabel.textColor = UIColor(red: 185/255, green: 28/255, blue: 28/255, alpha: 1.0) modernCategoryLabel.text = "SERTIFIKAT DICABUT" modernNomorLabel.translatesAutoresizingMaskIntoConstraints = false modernNomorLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold) modernNomorLabel.textColor = UIColor(red: 26/255, green: 32/255, blue: 44/255, alpha: 1.0) modernNomorLabel.numberOfLines = 1 titleStack.addArrangedSubview(modernCategoryLabel) titleStack.addArrangedSubview(modernNomorLabel) modernStatusPill.translatesAutoresizingMaskIntoConstraints = false modernStatusPill.layer.cornerRadius = 12 modernStatusPill.layer.masksToBounds = true modernStatusPill.backgroundColor = UIColor(red: 254/255, green: 226/255, blue: 226/255, alpha: 1.0) let statusDot = UIView() statusDot.translatesAutoresizingMaskIntoConstraints = false statusDot.layer.cornerRadius = 3.5 statusDot.backgroundColor = UIColor(red: 239/255, green: 68/255, blue: 68/255, alpha: 1.0) modernStatusLabel.translatesAutoresizingMaskIntoConstraints = false modernStatusLabel.font = UIFont.systemFont(ofSize: 11, weight: .bold) modernStatusLabel.textColor = UIColor(red: 185/255, green: 28/255, blue: 28/255, alpha: 1.0) modernStatusLabel.text = "DICABUT" let pillStack = UIStackView(arrangedSubviews: [statusDot, modernStatusLabel]) pillStack.translatesAutoresizingMaskIntoConstraints = false pillStack.axis = .horizontal pillStack.spacing = 5 pillStack.alignment = .center modernStatusPill.addSubview(pillStack) headerStack.addArrangedSubview(modernBadgeView) headerStack.addArrangedSubview(titleStack) headerStack.addArrangedSubview(modernStatusPill) // 2. Equipment Name modernPerangkatLabel.translatesAutoresizingMaskIntoConstraints = false modernPerangkatLabel.font = UIFont.systemFont(ofSize: 15, weight: .bold) modernPerangkatLabel.textColor = UIColor(red: 26/255, green: 32/255, blue: 44/255, alpha: 1.0) modernPerangkatLabel.numberOfLines = 2 modernContainer.addSubview(modernPerangkatLabel) // 3. Company Row let companyStack = UIStackView() companyStack.translatesAutoresizingMaskIntoConstraints = false companyStack.axis = .horizontal companyStack.spacing = 6 companyStack.alignment = .center modernContainer.addSubview(companyStack) modernCompanyIcon.translatesAutoresizingMaskIntoConstraints = false if #available(iOS 13.0, *) { modernCompanyIcon.image = UIImage(systemName: "building.2.fill") } modernCompanyIcon.tintColor = UIColor(red: 113/255, green: 128/255, blue: 150/255, alpha: 1.0) modernCompanyIcon.contentMode = .scaleAspectFit modernPemohonLabel.translatesAutoresizingMaskIntoConstraints = false modernPemohonLabel.font = UIFont.systemFont(ofSize: 13, weight: .medium) modernPemohonLabel.textColor = UIColor(red: 74/255, green: 85/255, blue: 104/255, alpha: 1.0) modernPemohonLabel.numberOfLines = 1 companyStack.addArrangedSubview(modernCompanyIcon) companyStack.addArrangedSubview(modernPemohonLabel) // 4. Models Card modernModelsCard.translatesAutoresizingMaskIntoConstraints = false modernModelsCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0) modernModelsCard.layer.cornerRadius = 8 modernModelsCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor modernModelsCard.layer.borderWidth = 1 modernContainer.addSubview(modernModelsCard) modernModelsTitle.translatesAutoresizingMaskIntoConstraints = false modernModelsTitle.font = UIFont.systemFont(ofSize: 10, weight: .semibold) modernModelsTitle.textColor = UIColor(red: 113/255, green: 128/255, blue: 150/255, alpha: 1.0) modernModelsTitle.text = "MERK / MODEL" modernModelsVal.translatesAutoresizingMaskIntoConstraints = false modernModelsVal.font = UIFont.systemFont(ofSize: 12, weight: .semibold) modernModelsVal.textColor = UIColor(red: 45/255, green: 55/255, blue: 72/255, alpha: 1.0) modernModelsVal.numberOfLines = 1 let modelsStack = UIStackView(arrangedSubviews: [modernModelsTitle, modernModelsVal]) modelsStack.translatesAutoresizingMaskIntoConstraints = false modelsStack.axis = .vertical modelsStack.spacing = 2 modernModelsCard.addSubview(modelsStack) // 5. Alasan Pencabutan Note Card modernAlasanCard.translatesAutoresizingMaskIntoConstraints = false modernAlasanCard.backgroundColor = UIColor(red: 255/255, green: 251/255, blue: 235/255, alpha: 1.0) modernAlasanCard.layer.cornerRadius = 8 modernAlasanCard.layer.borderColor = UIColor(red: 253/255, green: 230/255, blue: 138/255, alpha: 1.0).cgColor modernAlasanCard.layer.borderWidth = 1 modernContainer.addSubview(modernAlasanCard) modernAlasanIcon.translatesAutoresizingMaskIntoConstraints = false if #available(iOS 13.0, *) { modernAlasanIcon.image = UIImage(systemName: "exclamationmark.triangle.fill") } modernAlasanIcon.tintColor = UIColor(red: 217/255, green: 119/255, blue: 6/255, alpha: 1.0) modernAlasanIcon.contentMode = .scaleAspectFit modernAlasanLabel.translatesAutoresizingMaskIntoConstraints = false modernAlasanLabel.font = UIFont.systemFont(ofSize: 11, weight: .medium) modernAlasanLabel.textColor = UIColor(red: 146/255, green: 64/255, blue: 14/255, alpha: 1.0) modernAlasanLabel.numberOfLines = 0 let alasanContent = UIStackView(arrangedSubviews: [modernAlasanIcon, modernAlasanLabel]) alasanContent.translatesAutoresizingMaskIntoConstraints = false alasanContent.axis = .horizontal alasanContent.spacing = 8 alasanContent.alignment = .top modernAlasanCard.addSubview(alasanContent) // 6. Approval Flow Badges (Kasi, Kasub, Direktur) modernApprovalStack.translatesAutoresizingMaskIntoConstraints = false modernApprovalStack.axis = .horizontal modernApprovalStack.distribution = .fillEqually modernApprovalStack.spacing = 6 modernContainer.addSubview(modernApprovalStack) func createStepBadge(_ container: UIView, label: UILabel, role: String) { container.translatesAutoresizingMaskIntoConstraints = false container.layer.cornerRadius = 6 container.layer.masksToBounds = true label.translatesAutoresizingMaskIntoConstraints = false label.font = UIFont.systemFont(ofSize: 10, weight: .bold) label.textAlignment = .center label.text = role container.addSubview(label) NSLayoutConstraint.activate([ label.topAnchor.constraint(equalTo: container.topAnchor, constant: 4), label.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -4), label.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 4), label.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -4) ]) } createStepBadge(modernKasiBadge, label: modernKasiLabel, role: "Kasi") createStepBadge(modernKasubBadge, label: modernKasubLabel, role: "Kasub") createStepBadge(modernDirutBadge, label: modernDirutLabel, role: "Direktur") modernApprovalStack.addArrangedSubview(modernKasiBadge) modernApprovalStack.addArrangedSubview(modernKasubBadge) modernApprovalStack.addArrangedSubview(modernDirutBadge) // 7. Validity Footer Bar modernValidityCard.translatesAutoresizingMaskIntoConstraints = false modernValidityCard.backgroundColor = UIColor(red: 254/255, green: 242/255, blue: 242/255, alpha: 1.0) modernValidityCard.layer.cornerRadius = 10 modernContainer.addSubview(modernValidityCard) modernCalendarIcon.translatesAutoresizingMaskIntoConstraints = false if #available(iOS 13.0, *) { modernCalendarIcon.image = UIImage(systemName: "calendar") } modernCalendarIcon.tintColor = UIColor(red: 185/255, green: 28/255, blue: 28/255, alpha: 1.0) modernCalendarIcon.contentMode = .scaleAspectFit modernValidityLabel.translatesAutoresizingMaskIntoConstraints = false modernValidityLabel.font = UIFont.systemFont(ofSize: 11, weight: .medium) modernValidityLabel.textColor = UIColor(red: 153/255, green: 27/255, blue: 27/255, alpha: 1.0) modernAplIdLabel.translatesAutoresizingMaskIntoConstraints = false modernAplIdLabel.font = UIFont.systemFont(ofSize: 10, weight: .bold) modernAplIdLabel.textColor = UIColor(red: 185/255, green: 28/255, blue: 28/255, alpha: 1.0) let validityContentStack = UIStackView(arrangedSubviews: [modernCalendarIcon, modernValidityLabel]) validityContentStack.translatesAutoresizingMaskIntoConstraints = false validityContentStack.axis = .horizontal validityContentStack.spacing = 6 validityContentStack.alignment = .center let footerStack = UIStackView(arrangedSubviews: [validityContentStack, modernAplIdLabel]) footerStack.translatesAutoresizingMaskIntoConstraints = false footerStack.axis = .horizontal footerStack.distribution = .equalSpacing footerStack.alignment = .center modernValidityCard.addSubview(footerStack) // Constraints NSLayoutConstraint.activate([ headerStack.topAnchor.constraint(equalTo: modernContainer.topAnchor), headerStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), headerStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernBadgeView.widthAnchor.constraint(equalToConstant: 34), modernBadgeView.heightAnchor.constraint(equalToConstant: 34), modernBadgeIcon.centerXAnchor.constraint(equalTo: modernBadgeView.centerXAnchor), modernBadgeIcon.centerYAnchor.constraint(equalTo: modernBadgeView.centerYAnchor), modernBadgeIcon.widthAnchor.constraint(equalToConstant: 18), modernBadgeIcon.heightAnchor.constraint(equalToConstant: 18), statusDot.widthAnchor.constraint(equalToConstant: 7), statusDot.heightAnchor.constraint(equalToConstant: 7), pillStack.topAnchor.constraint(equalTo: modernStatusPill.topAnchor, constant: 5), pillStack.bottomAnchor.constraint(equalTo: modernStatusPill.bottomAnchor, constant: -5), pillStack.leadingAnchor.constraint(equalTo: modernStatusPill.leadingAnchor, constant: 10), pillStack.trailingAnchor.constraint(equalTo: modernStatusPill.trailingAnchor, constant: -10), modernPerangkatLabel.topAnchor.constraint(equalTo: headerStack.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), modernCompanyIcon.widthAnchor.constraint(equalToConstant: 14), modernCompanyIcon.heightAnchor.constraint(equalToConstant: 14), modernModelsCard.topAnchor.constraint(equalTo: companyStack.bottomAnchor, constant: 8), modernModelsCard.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernModelsCard.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modelsStack.topAnchor.constraint(equalTo: modernModelsCard.topAnchor, constant: 6), modelsStack.bottomAnchor.constraint(equalTo: modernModelsCard.bottomAnchor, constant: -6), modelsStack.leadingAnchor.constraint(equalTo: modernModelsCard.leadingAnchor, constant: 8), modelsStack.trailingAnchor.constraint(equalTo: modernModelsCard.trailingAnchor, constant: -8), modernAlasanCard.topAnchor.constraint(equalTo: modernModelsCard.bottomAnchor, constant: 8), modernAlasanCard.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernAlasanCard.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernAlasanIcon.widthAnchor.constraint(equalToConstant: 14), modernAlasanIcon.heightAnchor.constraint(equalToConstant: 14), alasanContent.topAnchor.constraint(equalTo: modernAlasanCard.topAnchor, constant: 8), alasanContent.bottomAnchor.constraint(equalTo: modernAlasanCard.bottomAnchor, constant: -8), alasanContent.leadingAnchor.constraint(equalTo: modernAlasanCard.leadingAnchor, constant: 8), alasanContent.trailingAnchor.constraint(equalTo: modernAlasanCard.trailingAnchor, constant: -8), modernApprovalStack.topAnchor.constraint(equalTo: modernAlasanCard.bottomAnchor, constant: 8), modernApprovalStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernApprovalStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernValidityCard.topAnchor.constraint(equalTo: modernApprovalStack.bottomAnchor, constant: 10), modernValidityCard.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernValidityCard.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernValidityCard.bottomAnchor.constraint(equalTo: modernContainer.bottomAnchor), modernCalendarIcon.widthAnchor.constraint(equalToConstant: 13), modernCalendarIcon.heightAnchor.constraint(equalToConstant: 13), footerStack.topAnchor.constraint(equalTo: modernValidityCard.topAnchor, constant: 8), footerStack.bottomAnchor.constraint(equalTo: modernValidityCard.bottomAnchor, constant: -8), footerStack.leadingAnchor.constraint(equalTo: modernValidityCard.leadingAnchor, constant: 10), footerStack.trailingAnchor.constraint(equalTo: modernValidityCard.trailingAnchor, constant: -10) ]) } private func updateBadgeState(_ container: UIView, label: UILabel, role: String, approved: Bool) { if approved { container.backgroundColor = UIColor(red: 232/255, green: 248/255, blue: 240/255, alpha: 1.0) label.textColor = UIColor(red: 16/255, green: 124/255, blue: 65/255, alpha: 1.0) label.text = "✓ \(role)" } else { container.backgroundColor = UIColor(red: 241/255, green: 245/255, blue: 249/255, alpha: 1.0) label.textColor = UIColor(red: 148/255, green: 163/255, blue: 184/255, alpha: 1.0) label.text = "○ \(role)" } } func updateViews(sertifikatDaftarPencabutan: SertifikatDaftarPencabutan) { card?.isInteractable = false setupModernLayout() let nomor = sertifikatDaftarPencabutan.nomor.isEmpty ? "-" : sertifikatDaftarPencabutan.nomor modernNomorLabel.text = nomor lblNo?.text = nomor let expFormatted = CommonHelper.formatDate(from: sertifikatDaftarPencabutan.exp) modernValidityLabel.text = "Kedaluwarsa: \(expFormatted)" lblExpDate?.text = "EXPIRED: \(expFormatted)" let cust = sertifikatDaftarPencabutan.cust_name.isEmpty ? "-" : sertifikatDaftarPencabutan.cust_name modernPemohonLabel.text = cust lblCustName?.text = cust let eqp = sertifikatDaftarPencabutan.eqp_name.isEmpty ? "-" : sertifikatDaftarPencabutan.eqp_name modernPerangkatLabel.text = eqp lblEqpName?.text = eqp let models = sertifikatDaftarPencabutan.models.isEmpty ? "-" : sertifikatDaftarPencabutan.models modernModelsVal.text = models lblModels?.text = models let alasan = sertifikatDaftarPencabutan.alasan.isEmpty ? "Tidak ada keterangan" : sertifikatDaftarPencabutan.alasan modernAlasanLabel.text = "Alasan: \(alasan)" lblKeterangan?.text = "KETERANGAN: \(alasan)" modernAplIdLabel.text = "ID: \(sertifikatDaftarPencabutan.apl_id)" lblAplikasiId?.text = "\(sertifikatDaftarPencabutan.apl_id)" // Update Approval Badges let isKasi = sertifikatDaftarPencabutan.kasiBatal() let isKasub = sertifikatDaftarPencabutan.kasubBatal() let isDirut = sertifikatDaftarPencabutan.dirutBatal() updateBadgeState(modernKasiBadge, label: modernKasiLabel, role: "Kasi", approved: isKasi) updateBadgeState(modernKasubBadge, label: modernKasubLabel, role: "Kasub", approved: isKasub) updateBadgeState(modernDirutBadge, label: modernDirutLabel, role: "Direktur", approved: isDirut) // Sync legacy checkboxes for storyboard compatibility cbKasi?.image = UIImage(named: isKasi ? "checked-box" : "unchecked-box") cbKasub?.image = UIImage(named: isKasub ? "checked-box" : "unchecked-box") cbDirektur?.image = UIImage(named: isDirut ? "checked-box" : "unchecked-box") } }