diff --git a/MVMCoreUI/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atoms/Views/Label/Label.swift index 013f7f11..b300b7bb 100644 --- a/MVMCoreUI/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label/Label.swift @@ -231,6 +231,7 @@ public typealias ActionBlock = () -> () attributedText = nil originalAttributedString = nil text = labelModel.text + hero = labelModel.hero Label.setLabel(self, withHTML: labelModel.html) let alignment = LabelAlignment(rawValue: labelModel.textAlignment ?? "") @@ -344,7 +345,6 @@ public typealias ActionBlock = () -> () } attributedText = attributedString originalAttributedString = attributedText - hero = labelModel.hero } } @@ -716,6 +716,7 @@ extension Label { public func reset() { text = nil attributedText = nil + hero = nil textAlignment = .left originalAttributedString = nil styleB2(true) diff --git a/MVMCoreUI/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atoms/Views/Label/LabelModel.swift index d7fb4fa3..cb9cc0a9 100644 --- a/MVMCoreUI/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atoms/Views/Label/LabelModel.swift @@ -10,6 +10,10 @@ import Foundation @objcMembers public class LabelModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "label" public var backgroundColor: Color? public var text: String @@ -24,6 +28,10 @@ import Foundation public var hero: Int? public var makeWholeViewClickable: Bool? + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case text @@ -43,11 +51,19 @@ import Foundation enum AttributeTypeKey: String, CodingKey { case type } - + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(text: String) { self.text = text } - + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) text = try typeContainer.decode(String.self, forKey: .text) diff --git a/MVMCoreUI/BaseClasses/TableViewCell.swift b/MVMCoreUI/BaseClasses/TableViewCell.swift index ac91f292..a301926c 100644 --- a/MVMCoreUI/BaseClasses/TableViewCell.swift +++ b/MVMCoreUI/BaseClasses/TableViewCell.swift @@ -198,8 +198,8 @@ import UIKit /// Adds the standard mvm style caret to the accessory view @objc public func addCaretViewAccessory() { guard accessoryView == nil else { return } + let caret = CaretView(lineWidth: 1) - caret.translatesAutoresizingMaskIntoConstraints = true caret.size = .small(.vertical) if let size = caret.size?.dimensions() { caret.frame = CGRect(origin: CGPoint.zero, size: size) @@ -217,11 +217,11 @@ import UIKit layoutIfNeeded() guard let heroLabel = findHeroLabel(views: contentView.subviews), let hero = heroLabel.hero else { return } let rect = Label.boundingRect(forCharacterRange: NSRange(location: hero, length: 1), in: heroLabel) - accessoryView?.center.y = contentView.convert(UIView(frame: rect).center, from: heroLabel).y + accessoryView?.center.y = convert(UIView(frame: rect).center, from: heroLabel).y heroAccessoryCenter = accessoryView?.center } - /// Traverses the view hierarchy for a 🦸‍♂️heroic Label. + /// Traverses the view hierarchy for a 🦸‍♂️ heroic Label. private func findHeroLabel(views: [UIView]) -> Label? { if views.isEmpty { diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift index 8f206e35..c964c6ed 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift @@ -9,11 +9,13 @@ import UIKit @objcMembers open class EyebrowHeadlineBodyLink: Container { + let stack = Stack(frame: .zero) let eyebrow = Label.commonLabelB3(true) let headline = Label.commonLabelB1(true) let body = Label.commonLabelB2(true) let link = Link() + var casteModel: EyebrowHeadlineBodyLinkModel? { get { return model as? EyebrowHeadlineBodyLinkModel } } @@ -21,7 +23,10 @@ import UIKit // MARK: - MFViewProtocol open override func setupView() { super.setupView() - stack.stackItems = [StackItem(andContain: eyebrow),StackItem(andContain: headline),StackItem(andContain: body),StackItem(andContain: link)] + stack.stackItems = [StackItem(andContain: eyebrow), + StackItem(andContain: headline), + StackItem(andContain: body), + StackItem(andContain: link)] addSubview(stack) NSLayoutConstraint.constraintPinSubview(toSuperview: stack) } @@ -42,7 +47,7 @@ import UIKit } // MARK:- ModelMoleculeViewProtocol - open override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + open override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.setWithModel(model, delegateObject, additionalData) eyebrow.setWithModel(casteModel?.eyebrow, delegateObject, additionalData) headline.setWithModel(casteModel?.headline, delegateObject, additionalData) @@ -50,7 +55,10 @@ import UIKit link.setWithModel(casteModel?.link, delegateObject, additionalData) // Create a stack model to use for the internal stack. - let stackModel = StackModel(molecules: [StackItemModel(gone: !eyebrow.hasText),StackItemModel(gone: !headline.hasText),StackItemModel(gone: !body.hasText),StackItemModel(gone: (link.titleLabel?.text?.count ?? 0) == 0)]) + let stackModel = StackModel(molecules: [StackItemModel(gone: !eyebrow.hasText), + StackItemModel(gone: !headline.hasText), + StackItemModel(gone: !body.hasText), + StackItemModel(gone: (link.titleLabel?.text?.count ?? 0) == 0)]) stackModel.spacing = 0 stack.model = stackModel stack.restack() diff --git a/MVMCoreUI/Organisms/Stack.swift b/MVMCoreUI/Organisms/Stack.swift index 4e7a3114..1f2fa288 100644 --- a/MVMCoreUI/Organisms/Stack.swift +++ b/MVMCoreUI/Organisms/Stack.swift @@ -51,7 +51,7 @@ open class Stack: Container where T: StackModelProtocol { super.init(frame: frame) } - public init(withJSON json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + public init(withJSON json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { super.init(frame: CGRect.zero) setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } @@ -63,9 +63,7 @@ open class Stack: Container where T: StackModelProtocol { // MARK: - MFViewProtocol public override func setupView() { super.setupView() - guard contentView.superview == nil else { - return - } + guard contentView.superview == nil else { return } MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0) translatesAutoresizingMaskIntoConstraints = false backgroundColor = .clear @@ -91,7 +89,7 @@ open class Stack: Container where T: StackModelProtocol { } } - public override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + public override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { let previousModel = self.model super.setWithModel(model, delegateObject, additionalData) removeAllItemViews() @@ -132,6 +130,7 @@ open class Stack: Container where T: StackModelProtocol { guard let model = molecule as? T else { return 0 } let horizontal = model.axis == .horizontal var estimatedHeight: CGFloat = 0 + for case let item in model.molecules { if item.gone { continue } let height = (MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(item) as? ModelMoleculeViewProtocol.Type)?.estimatedHeight(forRow: item, delegateObject: delegateObject) ?? 0 @@ -161,11 +160,10 @@ open class Stack: Container where T: StackModelProtocol { // MARK: - Subclassables /// Can be subclassed to create views when we get stack item models and have no views yet - func createStackItemsFromModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { - } + func createStackItemsFromModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { } /// Can be subclassed to set stack items with model when we already have views - func setStackItemsFromModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + func setStackItemsFromModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let models = stackModel?.molecules else { return } for (index, element) in models.enumerated() { (stackItems[index] as? ModelMoleculeViewProtocol)?.setWithModel(element, delegateObject, additionalData) @@ -178,6 +176,7 @@ open class Stack: Container where T: StackModelProtocol { guard let stackModel = stackModel else { return 0.0 } var totalSpace: CGFloat = 0.0 var firstMoleculeFound = false + for stackItemModel in stackModel.molecules { guard !stackItemModel.gone else { continue } let spacing = stackItemModel.spacing ?? stackModel.spacing @@ -214,9 +213,7 @@ open class Stack: Container where T: StackModelProtocol { if stackModel.axis == .vertical { if first { pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: stackModel.useStackSpacingBeforeFirstItem ? spacing : model.spacing ?? 0) - } else if let previousView = stackItems.last(where: { item in - return !model.gone - }) { + } else if let previousView = stackItems.last(where: { item in !model.gone }) { view.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: spacing).isActive = true } pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0) @@ -233,15 +230,13 @@ open class Stack: Container where T: StackModelProtocol { if first { // First horizontal item has no spacing by default unless told otherwise. pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: stackModel.useStackSpacingBeforeFirstItem ? spacing : model.spacing ?? 0) - } else if let previousView = stackItems.last(where: { item in - return !model.gone - }) { + } else if let previousView = stackItems.last(where: { item in !model.gone }) { view.leftAnchor.constraint(equalTo: previousView.rightAnchor, constant: spacing).isActive = true } pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0) pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0) if let percent = model.percent { - let multiplier = CGFloat(percent)/100.0 + let multiplier = CGFloat(percent) / 100.0 let constant = multiplier * totalSpacing view.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: multiplier, constant: -constant).isActive = true }