// // BalaiUjiCell.swift // Sirani // // Created by Anhar Solehudin on 03/04/19. // Copyright © 2019 Anhar Solehudin. All rights reserved. // import UIKit import MaterialComponents.MaterialCards protocol BalaiUjiCellDelegate: NSObjectProtocol { func openWeb(urlWeb: String?) } class BalaiUjiCell: UITableViewCell { @IBOutlet weak var card: MDCCard! @IBOutlet weak var lblIdBalai: UILabel! @IBOutlet weak var lblNoPenetapanTitle: UILabel! @IBOutlet weak var lblNoPenetapan: UILabel! @IBOutlet weak var lblTglPenetapanTitle: UILabel! @IBOutlet weak var lblTglPenetapan: UILabel! @IBOutlet weak var lblNamaBalaiUji: UILabel! @IBOutlet weak var lblRuangLingkup: UILabel! @IBOutlet weak var lblAlamat: UILabel! @IBOutlet weak var lblKontak: UILabel! @IBOutlet weak var btnWebsite: UIButton! var cellDelegate: BalaiUjiCellDelegate? var urlWeb: String? // Modern UI Elements private let modernContainer = UIView() private let modernBadgeView = UIView() private let modernBadgeIcon = UIImageView() private let modernNamaLabel = UILabel() private let modernCategoryLabel = UILabel() private let modernStatusPill = UIView() private let modernStatusLabel = UILabel() private let modernSpecStack = UIStackView() private let modernPenetapanCard = UIView() private let modernPenetapanTitle = UILabel() private let modernPenetapanVal = UILabel() private let modernTglCard = UIView() private let modernTglTitle = UILabel() private let modernTglVal = UILabel() private let modernLingkupCard = UIView() private let modernLingkupTitle = UILabel() private let modernLingkupVal = UILabel() private let modernAlamatStack = UIStackView() private let modernAlamatIcon = UIImageView() private let modernAlamatLabel = UILabel() private let modernKontakStack = UIStackView() private let modernKontakIcon = UIImageView() private let modernKontakLabel = UILabel() private let modernBtnWebsite = UIButton(type: .system) 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: "flask.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 titleStack = UIStackView() titleStack.axis = .vertical titleStack.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 = "BALAI UJI TERAKREDITASI" titleStack.addArrangedSubview(modernCategoryLabel) modernNamaLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold) modernNamaLabel.textColor = UIColor.siraniPrimaryBlue modernNamaLabel.numberOfLines = 1 modernNamaLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) titleStack.addArrangedSubview(modernNamaLabel) headerStack.addArrangedSubview(titleStack) // 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.text = "RESMI" 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. Mini Spec Cards (No Penetapan, Tgl Penetapan) modernSpecStack.translatesAutoresizingMaskIntoConstraints = false modernSpecStack.axis = .horizontal modernSpecStack.distribution = .fillEqually modernSpecStack.spacing = 8 modernContainer.addSubview(modernSpecStack) modernPenetapanCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0) modernPenetapanCard.layer.cornerRadius = 8 modernPenetapanCard.layer.borderWidth = 1 modernPenetapanCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor let pStack = UIStackView() pStack.translatesAutoresizingMaskIntoConstraints = false pStack.axis = .vertical pStack.spacing = 2 modernPenetapanCard.addSubview(pStack) modernPenetapanTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold) modernPenetapanTitle.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0) modernPenetapanTitle.text = "NO. PENETAPAN" pStack.addArrangedSubview(modernPenetapanTitle) modernPenetapanVal.font = UIFont.systemFont(ofSize: 11, weight: .semibold) modernPenetapanVal.textColor = UIColor(red: 40/255, green: 50/255, blue: 65/255, alpha: 1.0) pStack.addArrangedSubview(modernPenetapanVal) NSLayoutConstraint.activate([ pStack.topAnchor.constraint(equalTo: modernPenetapanCard.topAnchor, constant: 6), pStack.bottomAnchor.constraint(equalTo: modernPenetapanCard.bottomAnchor, constant: -6), pStack.leadingAnchor.constraint(equalTo: modernPenetapanCard.leadingAnchor, constant: 8), pStack.trailingAnchor.constraint(equalTo: modernPenetapanCard.trailingAnchor, constant: -8) ]) modernSpecStack.addArrangedSubview(modernPenetapanCard) modernTglCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0) modernTglCard.layer.cornerRadius = 8 modernTglCard.layer.borderWidth = 1 modernTglCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor let tStack = UIStackView() tStack.translatesAutoresizingMaskIntoConstraints = false tStack.axis = .vertical tStack.spacing = 2 modernTglCard.addSubview(tStack) modernTglTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold) modernTglTitle.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0) modernTglTitle.text = "TGL PENETAPAN" tStack.addArrangedSubview(modernTglTitle) modernTglVal.font = UIFont.systemFont(ofSize: 11, weight: .semibold) modernTglVal.textColor = UIColor(red: 40/255, green: 50/255, blue: 65/255, alpha: 1.0) tStack.addArrangedSubview(modernTglVal) NSLayoutConstraint.activate([ tStack.topAnchor.constraint(equalTo: modernTglCard.topAnchor, constant: 6), tStack.bottomAnchor.constraint(equalTo: modernTglCard.bottomAnchor, constant: -6), tStack.leadingAnchor.constraint(equalTo: modernTglCard.leadingAnchor, constant: 8), tStack.trailingAnchor.constraint(equalTo: modernTglCard.trailingAnchor, constant: -8) ]) modernSpecStack.addArrangedSubview(modernTglCard) // 4. Ruang Lingkup Card modernLingkupCard.translatesAutoresizingMaskIntoConstraints = false modernLingkupCard.backgroundColor = UIColor(red: 245/255, green: 249/255, blue: 255/255, alpha: 1.0) modernLingkupCard.layer.cornerRadius = 8 modernLingkupCard.layer.borderWidth = 1 modernLingkupCard.layer.borderColor = UIColor(red: 228/255, green: 236/255, blue: 248/255, alpha: 1.0).cgColor modernContainer.addSubview(modernLingkupCard) let lStack = UIStackView() lStack.translatesAutoresizingMaskIntoConstraints = false lStack.axis = .vertical lStack.spacing = 2 modernLingkupCard.addSubview(lStack) modernLingkupTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold) modernLingkupTitle.textColor = UIColor.siraniPrimaryBlue modernLingkupTitle.text = "RUANG LINGKUP PENGUJIAN" lStack.addArrangedSubview(modernLingkupTitle) modernLingkupVal.font = UIFont.systemFont(ofSize: 12, weight: .semibold) modernLingkupVal.textColor = UIColor(red: 30/255, green: 45/255, blue: 65/255, alpha: 1.0) modernLingkupVal.numberOfLines = 2 lStack.addArrangedSubview(modernLingkupVal) NSLayoutConstraint.activate([ lStack.topAnchor.constraint(equalTo: modernLingkupCard.topAnchor, constant: 6), lStack.bottomAnchor.constraint(equalTo: modernLingkupCard.bottomAnchor, constant: -6), lStack.leadingAnchor.constraint(equalTo: modernLingkupCard.leadingAnchor, constant: 10), lStack.trailingAnchor.constraint(equalTo: modernLingkupCard.trailingAnchor, constant: -10) ]) // 5. Alamat Stack modernAlamatStack.translatesAutoresizingMaskIntoConstraints = false modernAlamatStack.axis = .horizontal modernAlamatStack.spacing = 6 modernAlamatStack.alignment = .top if #available(iOS 13.0, *) { modernAlamatIcon.image = UIImage(systemName: "mappin.and.ellipse") } modernAlamatIcon.tintColor = UIColor(red: 120/255, green: 135/255, blue: 155/255, alpha: 1.0) modernAlamatIcon.contentMode = .scaleAspectFit modernAlamatIcon.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ modernAlamatIcon.widthAnchor.constraint(equalToConstant: 14), modernAlamatIcon.heightAnchor.constraint(equalToConstant: 14) ]) modernAlamatStack.addArrangedSubview(modernAlamatIcon) modernAlamatLabel.font = UIFont.systemFont(ofSize: 11, weight: .medium) modernAlamatLabel.textColor = UIColor(red: 90/255, green: 105/255, blue: 125/255, alpha: 1.0) modernAlamatLabel.numberOfLines = 2 modernAlamatStack.addArrangedSubview(modernAlamatLabel) modernContainer.addSubview(modernAlamatStack) // 6. Kontak Stack & Button Website let footerStack = UIStackView() footerStack.translatesAutoresizingMaskIntoConstraints = false footerStack.axis = .horizontal footerStack.spacing = 8 footerStack.alignment = .center modernContainer.addSubview(footerStack) if #available(iOS 13.0, *) { modernKontakIcon.image = UIImage(systemName: "phone.fill") } modernKontakIcon.tintColor = UIColor(red: 120/255, green: 135/255, blue: 155/255, alpha: 1.0) modernKontakIcon.contentMode = .scaleAspectFit modernKontakIcon.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ modernKontakIcon.widthAnchor.constraint(equalToConstant: 12), modernKontakIcon.heightAnchor.constraint(equalToConstant: 12) ]) footerStack.addArrangedSubview(modernKontakIcon) modernKontakLabel.font = UIFont.systemFont(ofSize: 11, weight: .medium) modernKontakLabel.textColor = UIColor(red: 90/255, green: 105/255, blue: 125/255, alpha: 1.0) modernKontakLabel.numberOfLines = 1 footerStack.addArrangedSubview(modernKontakLabel) let spacer = UIView() spacer.setContentHuggingPriority(.defaultLow, for: .horizontal) footerStack.addArrangedSubview(spacer) modernBtnWebsite.translatesAutoresizingMaskIntoConstraints = false modernBtnWebsite.setTitle("🌐 Website", for: .normal) modernBtnWebsite.titleLabel?.font = UIFont.systemFont(ofSize: 11, weight: .bold) modernBtnWebsite.setTitleColor(UIColor.siraniPrimaryBlue, for: .normal) modernBtnWebsite.backgroundColor = UIColor(red: 235/255, green: 242/255, blue: 252/255, alpha: 1.0) modernBtnWebsite.layer.cornerRadius = 8 modernBtnWebsite.contentEdgeInsets = UIEdgeInsets(top: 5, left: 10, bottom: 5, right: 10) modernBtnWebsite.addTarget(self, action: #selector(onBtnWebsiteTap(_:)), for: .touchUpInside) footerStack.addArrangedSubview(modernBtnWebsite) 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), modernSpecStack.topAnchor.constraint(equalTo: divider.bottomAnchor, constant: 10), modernSpecStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernSpecStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernLingkupCard.topAnchor.constraint(equalTo: modernSpecStack.bottomAnchor, constant: 8), modernLingkupCard.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernLingkupCard.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernAlamatStack.topAnchor.constraint(equalTo: modernLingkupCard.bottomAnchor, constant: 8), modernAlamatStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernAlamatStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), footerStack.topAnchor.constraint(equalTo: modernAlamatStack.bottomAnchor, constant: 8), footerStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), footerStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), footerStack.bottomAnchor.constraint(equalTo: modernContainer.bottomAnchor) ]) } func updateViews(balaiUji: BalaiUji) { setupCardVisuals() setupModernLayout() card.isInteractable = false modernNamaLabel.text = balaiUji.nama.isEmpty ? "-" : balaiUji.nama modernPenetapanVal.text = balaiUji.balai_id == 0 ? "-" : String(balaiUji.balai_id) let tglFormatted = CommonHelper.formatDate(from: balaiUji.tanggal_terbit) modernTglVal.text = tglFormatted.isEmpty ? "-" : tglFormatted modernLingkupVal.text = balaiUji.ruang_lingkup.isEmpty ? "-" : balaiUji.ruang_lingkup modernAlamatLabel.text = balaiUji.tempat.isEmpty ? "-" : balaiUji.tempat modernKontakLabel.text = balaiUji.kontak.isEmpty ? "-" : balaiUji.kontak urlWeb = balaiUji.website modernBtnWebsite.isHidden = (urlWeb == nil || urlWeb!.isEmpty || urlWeb == "null") } @IBAction func onBtnWebsiteTap(_ sender: Any) { cellDelegate?.openWeb(urlWeb: urlWeb) } }