| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- //
- // 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)
- }
- }
|