// // CollectionViewCell.swift // MVMCoreUI // // Created by Scott Pfeil on 4/6/20. // Copyright © 2020 Verizon Wireless. All rights reserved. // import Foundation /// A base collection view cell with basic mvm functionality. open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCoreViewProtocol, CollectionTemplateItemProtocol, MFButtonProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- // Convenience helpers open var molecule: MoleculeViewProtocol? public let containerHelper = ContainerHelper() open var model: CollectionItemModelProtocol? /// The width, used for establishing columns open var width: CGFloat? private var initialSetupPerformed = false // MARK: - Inits public override init(frame: CGRect) { super.init(frame: .zero) initialSetup() } public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) initialSetup() } private func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true setupView() } } // MARK: - Helpers /// Convenience function. Adds a molecule to the view. open func addMolecule(_ molecule: MoleculeViewProtocol) { contentView.addSubview(molecule) containerHelper.constrainView(molecule) self.molecule = molecule } // MARK: - MVMCoreViewProtocol open func setupView() { isAccessibilityElement = false contentView.isAccessibilityElement = false insetsLayoutMarginsFromSafeArea = false contentView.insetsLayoutMarginsFromSafeArea = false contentView.preservesSuperviewLayoutMargins = false MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0) } open func updateView(_ size: CGFloat) { if let model = model as? ContainerModelProtocol { containerHelper.updateViewMargins(contentView, model: model, size: size) } (molecule as? MVMCoreViewProtocol)?.updateView(size) } // MARK: - MoleculeViewProtocol open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let model = model as? CollectionItemModelProtocol else { return } self.model = model if let moleculeModel = model as? MoleculeModelProtocol, let backgroundColor = moleculeModel.backgroundColor { self.backgroundColor = backgroundColor.uiColor } // align if needed. if let model = model as? ContainerModelProtocol { containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol) } } open func reset() { molecule?.reset() backgroundColor = .clear width = nil } // MARK: Overridables // Base classes need to implement these functions otherwise swift won't respect the subclass functions and use the ones in the protocol extension instead. open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { return model.moleculeName } open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return nil } open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { return nil } //-------------------------------------------------- // MARK: - CollectionTemplateItemProtocol //-------------------------------------------------- public func set(width: CGFloat) { self.width = width } // MARK: - Override open func shouldSelect(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Bool { if let action = model?.action { Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData) } return true } open func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {} // Column logic, set width. override open func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes) guard let width = width else { return autoLayoutAttributes } let targetSize = CGSize(width: width, height: 0) let newSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow) let newFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: newSize) autoLayoutAttributes.frame = newFrame return autoLayoutAttributes } }