// // EmployeeTableViewCell.swift // EmployeeDirectory // // Created by Matt Bruce on 1/20/25. // import UIKit import Combine /// This is the Cell used in the EmployeesTableViewController to show /// the properties of an Employee model. public class EmployeeTableViewCell: UITableViewCell { /// Used in the TableView registration static let identifier = "EmployeeTableViewCell" // MARK: - Properties /// UI Elements private let photoImageView = UIImageView() private let nameLabel = UILabel() private let emailLabel = UILabel() private let teamLabel = UILabel() private let employeeTypeLabel = UILabel() private let phoneLabel = UILabel() private let bioLabel = UILabel() private let stackView = UIStackView() /// Used for grabbing the photo private var smallPhotoSubscriber: AnyCancellable? // MARK: - Initializer public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupUI() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - Private Methods private func setupUI() { // Configure photoImageView photoImageView.contentMode = .scaleAspectFill photoImageView.clipsToBounds = true photoImageView.layer.cornerRadius = 25 photoImageView.translatesAutoresizingMaskIntoConstraints = false photoImageView.image = UIImage(systemName: "person.crop.circle") // Configure labels with text styles nameLabel.font = UIFont.preferredFont(forTextStyle: .headline) // Bold, prominent text nameLabel.adjustsFontForContentSizeCategory = true // Adapts to Dynamic Type emailLabel.font = UIFont.preferredFont(forTextStyle: .body) emailLabel.textColor = .blue emailLabel.adjustsFontForContentSizeCategory = true // Adapts to Dynamic Type teamLabel.font = UIFont.preferredFont(forTextStyle: .subheadline) // Secondary, smaller text teamLabel.textColor = .gray teamLabel.adjustsFontForContentSizeCategory = true // Adapts to Dynamic Type employeeTypeLabel.font = UIFont.preferredFont(forTextStyle: .subheadline) employeeTypeLabel.adjustsFontForContentSizeCategory = true // Adapts to Dynamic Type phoneLabel.font = UIFont.preferredFont(forTextStyle: .body) // Standard body text phoneLabel.textColor = .darkGray phoneLabel.adjustsFontForContentSizeCategory = true// Adapts to Dynamic Type bioLabel.font = UIFont.preferredFont(forTextStyle: .footnote) // Smaller text for additional info bioLabel.numberOfLines = 0 bioLabel.textColor = .lightGray bioLabel.adjustsFontForContentSizeCategory = true // Adapts to Dynamic Type // Configure stackView stackView.axis = .vertical stackView.spacing = 5 stackView.translatesAutoresizingMaskIntoConstraints = false // Add labels to stackView stackView.addArrangedSubview(nameLabel) stackView.addArrangedSubview(teamLabel) stackView.addArrangedSubview(employeeTypeLabel) stackView.addArrangedSubview(phoneLabel) stackView.addArrangedSubview(emailLabel) stackView.addArrangedSubview(bioLabel) // Add subviews contentView.addSubview(photoImageView) contentView.addSubview(stackView) // Add constraints NSLayoutConstraint.activate([ photoImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10), photoImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), photoImageView.widthAnchor.constraint(equalToConstant: 50), photoImageView.heightAnchor.constraint(equalToConstant: 50), stackView.leadingAnchor.constraint(equalTo: photoImageView.trailingAnchor, constant: 10), stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10), stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10), stackView.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: -10) ]) } // MARK: - Public Methods /// Override for setting back to a default state public override func prepareForReuse() { super.prepareForReuse() smallPhotoSubscriber = nil photoImageView.image = UIImage(systemName: "person.crop.circle") nameLabel.text = nil emailLabel.text = nil teamLabel.text = nil employeeTypeLabel.text = nil phoneLabel.text = nil bioLabel.text = nil } /// Configures the UI Elements with the properties of the EmployeeCellViewModel. /// - Parameter viewModel: Employee Model wrapped for Cell. public func configure(with viewModel: EmployeeCellViewModel) { // Bind the image to the photoImageView smallPhotoSubscriber = viewModel.$smallPhoto .receive(on: DispatchQueue.main) .sink { [weak self] image in self?.photoImageView.image = image } // Bind data to UI components nameLabel.text = viewModel.fullName emailLabel.text = viewModel.emailAddress teamLabel.text = viewModel.team employeeTypeLabel.text = viewModel.employeeType phoneLabel.text = viewModel.phoneNumber bioLabel.text = viewModel.biography // Dynamically show or hide elements based on their content phoneLabel.isHidden = viewModel.phoneNumber == nil bioLabel.isHidden = viewModel.biography == nil } }