251 lines
11 KiB
Swift
251 lines
11 KiB
Swift
//
|
|
// MoleculeTableViewCell.swift
|
|
// MVMCoreUI
|
|
//
|
|
// Created by Scott Pfeil on 4/18/19.
|
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
@objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol {
|
|
|
|
open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)?
|
|
open var json: [AnyHashable: Any]?
|
|
|
|
// In updateView, will set padding to default.
|
|
open var updateViewHorizontalDefaults = true
|
|
open var updateViewVerticalDefaults = true
|
|
|
|
// For the accessory view convenience.
|
|
public var caretView: CaretView?
|
|
private var caretViewWidthSizeObject: MFSizeObject?
|
|
private var caretViewHeightSizeObject: MFSizeObject?
|
|
|
|
// For separation between cells.
|
|
public var topSeparatorView: SeparatorView?
|
|
public var bottomSeparatorView: SeparatorView?
|
|
public enum SeparatorFrequency: String {
|
|
case All = "all"
|
|
case AllExceptTop = "allExceptTop"
|
|
case AllExceptBottom = "allExceptBottom"
|
|
case Between = "between"
|
|
}
|
|
|
|
// MARK: - Inits
|
|
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
|
setupView()
|
|
}
|
|
|
|
public required init?(coder aDecoder: NSCoder) {
|
|
super.init(coder: aDecoder)
|
|
setupView()
|
|
}
|
|
|
|
// MARK: - MFViewProtocol
|
|
public func updateView(_ size: CGFloat) {
|
|
MFStyler.setDefaultMarginsFor(self, size: size, horizontal: updateViewHorizontalDefaults, vertical: updateViewVerticalDefaults)
|
|
if #available(iOS 11.0, *) {
|
|
if accessoryView != nil {
|
|
// Smaller left margin if accessory view.
|
|
var margin = directionalLayoutMargins
|
|
margin.trailing = 16
|
|
contentView.directionalLayoutMargins = margin
|
|
} else {
|
|
contentView.directionalLayoutMargins = directionalLayoutMargins
|
|
}
|
|
topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
|
bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading)
|
|
} else {
|
|
if accessoryView != nil {
|
|
// Smaller left margin if accessory view.
|
|
var margin = layoutMargins
|
|
margin.right = 16
|
|
contentView.layoutMargins = margin
|
|
} else {
|
|
contentView.layoutMargins = layoutMargins
|
|
}
|
|
topSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
|
|
bottomSeparatorView?.setLeftAndRightPinConstant(layoutMargins.left)
|
|
}
|
|
|
|
molecule?.updateView(size)
|
|
if let _ = accessoryView, let caretView = caretView, let widthObject = caretViewWidthSizeObject, let heightObject = caretViewHeightSizeObject {
|
|
caretView.frame = CGRect(x: 0, y: 0, width: widthObject.getValueBased(onSize: size), height: heightObject.getValueBased(onSize: size))
|
|
}
|
|
topSeparatorView?.updateView(size)
|
|
bottomSeparatorView?.updateView(size)
|
|
}
|
|
|
|
public func setupView() {
|
|
selectionStyle = .none
|
|
if #available(iOS 11.0, *) {
|
|
insetsLayoutMarginsFromSafeArea = false
|
|
contentView.insetsLayoutMarginsFromSafeArea = false
|
|
contentView.preservesSuperviewLayoutMargins = false
|
|
}
|
|
}
|
|
|
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
|
public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
|
self.json = json;
|
|
|
|
if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") {
|
|
updateViewHorizontalDefaults = useHorizontalMargins
|
|
}
|
|
if let useVerticalMargins = json?.optionalBoolForKey("useVerticalMargins") {
|
|
updateViewVerticalDefaults = useVerticalMargins
|
|
}
|
|
|
|
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
|
backgroundColor = UIColor.mfGet(forHex: backgroundColorString)
|
|
}
|
|
|
|
// Add the caret if there is an action and it's not declared hidden.
|
|
if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") {
|
|
addCaretViewAccessory()
|
|
} else {
|
|
accessoryView = nil
|
|
}
|
|
|
|
// override the separator
|
|
if let separator = json?.optionalDictionaryForKey("separator") {
|
|
addSeparatorsIfNeeded()
|
|
bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData)
|
|
}
|
|
|
|
guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else {
|
|
return
|
|
}
|
|
if molecule == nil {
|
|
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
|
|
contentView.addSubview(moleculeView)
|
|
let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
|
|
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values))
|
|
if standardConstraints {
|
|
let constraint = contentView.heightAnchor.constraint(equalToConstant: 80)
|
|
constraint.priority = .defaultLow
|
|
constraint.isActive = true
|
|
}
|
|
molecule = moleculeView
|
|
}
|
|
} else {
|
|
molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
|
|
}
|
|
|
|
// This molecule will by default handle margins.
|
|
if let castView = molecule as? MVMCoreUIViewConstrainingProtocol {
|
|
castView.shouldSetHorizontalMargins?(false)
|
|
castView.shouldSetVerticalMargins?(false)
|
|
}
|
|
}
|
|
|
|
public func reset() {
|
|
molecule?.reset?()
|
|
updateViewVerticalDefaults = true
|
|
updateViewHorizontalDefaults = true
|
|
backgroundColor = .white
|
|
}
|
|
|
|
public static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
|
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else {
|
|
return 80
|
|
}
|
|
return max(80, height)
|
|
}
|
|
|
|
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
|
guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else {
|
|
return nil
|
|
}
|
|
return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName)
|
|
}
|
|
|
|
public static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
|
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
|
|
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON) else {
|
|
return nil
|
|
}
|
|
return theClass.requiredModules?(moleculeJSON, delegateObject: delegateObject, error: error)
|
|
}
|
|
|
|
// MARK: - Arrow
|
|
/// Adds the standard mvm style caret to the accessory view
|
|
public func addCaretViewAccessory() {
|
|
guard accessoryView == nil else {
|
|
return
|
|
}
|
|
let width: CGFloat = 6
|
|
let height: CGFloat = 10
|
|
caretView = CaretView(lineThickness: CaretView.thin)
|
|
caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
|
caretViewWidthSizeObject = MFSizeObject(standardSize: width, standardiPadPortraitSize: 9)
|
|
caretViewHeightSizeObject = MFSizeObject(standardSize: height, standardiPadPortraitSize: 16)
|
|
accessoryView = caretView
|
|
}
|
|
|
|
// MARK: - MoleculeListCellProtocol
|
|
/// For when the separator between cells shows using json and frequency. Default is type: standard, frequency: allExceptTop.
|
|
public func setSeparatorWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) {
|
|
addSeparatorsIfNeeded()
|
|
if let json = json {
|
|
topSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
|
bottomSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
|
if let separatorFrequencyString = json.optionalStringForKey("frequency"), let separatorFrequency = SeparatorFrequency(rawValue: separatorFrequencyString) {
|
|
setSeparatorFrequency(separatorFrequency, indexPath: indexPath)
|
|
}
|
|
} else {
|
|
topSeparatorView?.hide()
|
|
bottomSeparatorView?.setAsLight()
|
|
setSeparatorFrequency(MoleculeTableViewCell.SeparatorFrequency.AllExceptTop, indexPath: indexPath)
|
|
}
|
|
}
|
|
|
|
public func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
|
if let actionMap = json?.optionalDictionaryForKey("actionMap") {
|
|
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
|
|
}
|
|
}
|
|
|
|
// MARK: - Separator
|
|
func addSeparatorsIfNeeded() {
|
|
if topSeparatorView == nil {
|
|
topSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionTop)
|
|
topSeparatorView?.hide()
|
|
}
|
|
if bottomSeparatorView == nil {
|
|
bottomSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot)
|
|
bottomSeparatorView?.hide()
|
|
}
|
|
}
|
|
|
|
/// For when the separator between cells shows.
|
|
public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) {
|
|
switch separatorFrequency {
|
|
case .All:
|
|
if indexPath.row == 0 {
|
|
topSeparatorView?.show()
|
|
} else {
|
|
topSeparatorView?.hide()
|
|
}
|
|
bottomSeparatorView?.show()
|
|
case .AllExceptBottom:
|
|
topSeparatorView?.show()
|
|
bottomSeparatorView?.hide()
|
|
case .Between:
|
|
if indexPath.row == 0 {
|
|
topSeparatorView?.hide()
|
|
} else {
|
|
topSeparatorView?.show()
|
|
}
|
|
bottomSeparatorView?.hide()
|
|
case .AllExceptTop:
|
|
fallthrough
|
|
default:
|
|
topSeparatorView?.hide()
|
|
bottomSeparatorView?.show()
|
|
}
|
|
}
|
|
}
|