diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index 54a12612..b98e72a5 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -352,6 +352,45 @@ } - (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { + // Only treated as a container if we are constraining a molecule. + if (!self.constrainedView) { + [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; + } + if (self.shouldSetupMoleculeFromJSON) { + NSDictionary *moleculeJSON = [json dict:KeyMolecule]; + if (self.molecule) { + [self.molecule setWithJSON:moleculeJSON delegateObject:delegateObject additionalData:additionalData]; + } else if (moleculeJSON) { + UIView *molecule = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] createMoleculeForJSON:moleculeJSON delegateObject:delegateObject constrainIfNeeded:true]; + if (molecule) { + [self addMolecule:molecule]; + } + self.molecule = molecule; + [self setMoleculeAccessibility]; + } + } else { + [self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; + } + + NSNumber *useHorizontalMargins = [json optionalNumberForKey:@"useHorizontalMargins"]; + if (useHorizontalMargins) { + self.updateViewHorizontalDefaults = [useHorizontalMargins boolValue]; + } + NSNumber *useVerticalMargins = [json optionalNumberForKey:@"useVerticalMargins"]; + if (useVerticalMargins) { + self.updateViewVerticalDefaults = [useVerticalMargins boolValue]; + } + + // Set the alignment for the stack in the containing view. The json driven value is for the axis direction alignment. + NSString *alignment = [json string:@"horizontalAlignment"]; + if (alignment) { + [self alignHorizontal:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; + } + alignment = [json string:@"verticalAlignment"]; + if (alignment) { + [self alignVertical:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; + } + if ([self.molecule respondsToSelector:@selector(copyBackgroundColor)] && [self.molecule performSelector:@selector(copyBackgroundColor)]) { self.backgroundColor = self.molecule.backgroundColor; } diff --git a/MVMCoreUI/BaseClasses/View.swift b/MVMCoreUI/BaseClasses/View.swift index 4691f8e7..d3843f43 100644 --- a/MVMCoreUI/BaseClasses/View.swift +++ b/MVMCoreUI/BaseClasses/View.swift @@ -61,6 +61,7 @@ extension View: MVMCoreViewProtocol { open func setupView() { translatesAutoresizingMaskIntoConstraints = false insetsLayoutMarginsFromSafeArea = false + MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0) } } diff --git a/MVMCoreUI/Models/Molecules/FooterModel.swift b/MVMCoreUI/Models/Molecules/FooterModel.swift index 757e2fd5..e31ec1fc 100644 --- a/MVMCoreUI/Models/Molecules/FooterModel.swift +++ b/MVMCoreUI/Models/Molecules/FooterModel.swift @@ -16,11 +16,33 @@ import Foundation enum FooterCodingKeys: String, CodingKey { case backgroundColor } + + /// Defaults to set + func setDefaults() { + if useHorizontalMargins == nil { + useHorizontalMargins = true + } + if useVerticalMargins == nil { + useVerticalMargins = true + } + if topMarginPadding == nil { + topMarginPadding = PaddingDefaultVerticalSpacing + } + if bottomMarginPadding == nil { + bottomMarginPadding = PaddingDefaultVerticalSpacing + } + } + + public override init(with moleculeModel: MoleculeProtocol) { + super.init(with: moleculeModel) + setDefaults() + } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: FooterCodingKeys.self) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) try super.init(from: decoder) + setDefaults() } public override func encode(to encoder: Encoder) throws { diff --git a/MVMCoreUI/Models/Molecules/HeaderModel.swift b/MVMCoreUI/Models/Molecules/HeaderModel.swift index 1e4ab9f2..4499d313 100644 --- a/MVMCoreUI/Models/Molecules/HeaderModel.swift +++ b/MVMCoreUI/Models/Molecules/HeaderModel.swift @@ -18,19 +18,34 @@ import Foundation case line case backgroundColor } - - required public init(from decoder: Decoder) throws { - try super.init(from: decoder) - let typeContainer = try decoder.container(keyedBy: HeaderCodingKeys.self) - line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) - - // Default Values + + /// Defaults to set + func setDefaults() { + if useHorizontalMargins == nil { + useHorizontalMargins = true + } + if useVerticalMargins == nil { + useVerticalMargins = true + } if topMarginPadding == nil { topMarginPadding = PaddingDefaultVerticalSpacing } if bottomMarginPadding == nil { bottomMarginPadding = PaddingDefaultVerticalSpacing } + line?.type = .heavy + } + + public override init(with moleculeModel: MoleculeProtocol) { + super.init(with: moleculeModel) + setDefaults() + } + + required public init(from decoder: Decoder) throws { + try super.init(from: decoder) + let typeContainer = try decoder.container(keyedBy: HeaderCodingKeys.self) + line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) + setDefaults() } public override func encode(to encoder: Encoder) throws { diff --git a/MVMCoreUI/Molecules/Items/ListItemModel.swift b/MVMCoreUI/Molecules/Items/ListItemModel.swift index 24cb05e0..cd0b1dc3 100644 --- a/MVMCoreUI/Molecules/Items/ListItemModel.swift +++ b/MVMCoreUI/Molecules/Items/ListItemModel.swift @@ -24,6 +24,28 @@ import MVMCore case line case style } + + /// Defaults to set + func setDefaults() { + style = "standard" + if useHorizontalMargins == nil { + useHorizontalMargins = true + } + if useVerticalMargins == nil { + useVerticalMargins = true + } + if topMarginPadding == nil { + topMarginPadding = 24 + } + if bottomMarginPadding == nil { + bottomMarginPadding = 24 + } + } + + public override init(with moleculeModel: MoleculeProtocol) { + super.init(with: moleculeModel) + setDefaults() + } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: ListItemCodingKeys.self) @@ -34,15 +56,8 @@ import MVMCore if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) { self.style = style } - try super.init(from: decoder) - - if useHorizontalMargins == nil { - useHorizontalMargins = true - } - if useVerticalMargins == nil { - useVerticalMargins = true - } + setDefaults() } public override func encode(to encoder: Encoder) throws { diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 3733ea6e..30eb9a4a 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -13,13 +13,12 @@ import UIKit // MARK: - MVMCoreUIMoleculeViewProtocol public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.setWithModel(model, delegateObject, additionalData) - - guard let model = model, - let moleculeModel = (model as? ListItemModel)?.molecule, - let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject, true) else { - return + guard let moleculeModel = (model as? ListItemModel)?.molecule else { return } + if molecule != nil { + (molecule as? ModelMoleculeViewProtocol)?.setWithModel(moleculeModel, delegateObject, additionalData) + } else if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject, true) { + addMolecule(moleculeView) } - addMolecule(moleculeView) } public override class func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { diff --git a/MVMCoreUI/Molecules/Items/StackItemModel.swift b/MVMCoreUI/Molecules/Items/StackItemModel.swift index a5128f1b..d19f2401 100644 --- a/MVMCoreUI/Molecules/Items/StackItemModel.swift +++ b/MVMCoreUI/Molecules/Items/StackItemModel.swift @@ -12,12 +12,12 @@ import Foundation public static var identifier: String = "stackItem" public var backgroundColor: Color? public var spacing: CGFloat? - public var percentage: Int? = 0 + public var percent: Int? public var gone: Bool = false enum MoleculeStackItemCodingKeys: String, CodingKey { case spacing - case percentage + case percent case gone } @@ -28,7 +28,7 @@ import Foundation required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: MoleculeStackItemCodingKeys.self) spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) - percentage = try typeContainer.decodeIfPresent(Int.self, forKey: .percentage) + percent = try typeContainer.decodeIfPresent(Int.self, forKey: .percent) if let gone = try typeContainer.decodeIfPresent(Bool.self, forKey: .gone) { self.gone = gone } @@ -39,7 +39,7 @@ import Foundation try super.encode(to: encoder) var container = encoder.container(keyedBy: MoleculeStackItemCodingKeys.self) try container.encodeIfPresent(spacing, forKey: .spacing) - try container.encodeIfPresent(percentage, forKey: .percentage) + try container.encodeIfPresent(percent, forKey: .percent) try container.encode(gone, forKey: .gone) } } diff --git a/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift b/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift index bde3ab6f..ac9fe240 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift @@ -8,8 +8,8 @@ import UIKit -@objcMembers public class CornerLabels: ViewConstrainingView { - +@objcMembers public class CornerLabels: View { + var middleView: UIView? let topLeftLabel = Label.commonLabelB1(true) let topRightLabel = Label.commonLabelB1(true) let bottomLeftLabel = Label.commonLabelB3(true) @@ -38,18 +38,19 @@ import UIKit var topLabelToMoleculeConstraint: NSLayoutConstraint? var bottomLabelToMoleculeConstraint: NSLayoutConstraint? - public override func addMolecule(_ molecule: UIView) { - insertSubview(molecule, at: 0) + public func addMiddleView(_ view: UIView) { + insertSubview(view, at: 0) topLabelToMoleculeConstraint?.isActive = false bottomLabelToMoleculeConstraint?.isActive = false - molecule.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true - layoutMarginsGuide.rightAnchor.constraint(equalTo: molecule.rightAnchor).isActive = true + view.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor).isActive = true + layoutMarginsGuide.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true - topLabelToMoleculeConstraint = molecule.topAnchor.constraint(equalTo: topLabelsView.bottomAnchor, constant: spaceAboveMolecule) + topLabelToMoleculeConstraint = view.topAnchor.constraint(equalTo: topLabelsView.bottomAnchor, constant: spaceAboveMolecule) topLabelToMoleculeConstraint?.isActive = true - bottomLabelToMoleculeConstraint = bottomLabelsView.topAnchor.constraint(equalTo: molecule.bottomAnchor, constant: spaceBelowMolecule) + bottomLabelToMoleculeConstraint = bottomLabelsView.topAnchor.constraint(equalTo: view.bottomAnchor, constant: spaceBelowMolecule) bottomLabelToMoleculeConstraint?.isActive = true + self.middleView = view } // MARK: - MVMCoreViewProtocol @@ -59,12 +60,11 @@ import UIKit topRightLabel.updateView(size) bottomLeftLabel.updateView(size) bottomRightLabel.updateView(size) + (middleView as? MVMCoreViewProtocol)?.updateView(size) } public override func setupView() { super.setupView() - shouldSetupMoleculeFromJSON = true - guard topLeftLabel.superview == nil else { return } @@ -141,17 +141,6 @@ import UIKit } // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - topLeftLabel.setWithJSON(json?.optionalDictionaryForKey("topLeftLabel"), delegateObject: delegateObject, additionalData: additionalData) - topRightLabel.setWithJSON(json?.optionalDictionaryForKey("topRightLabel"), delegateObject: delegateObject, additionalData: additionalData) - bottomLeftLabel.setWithJSON(json?.optionalDictionaryForKey("bottomLeftLabel"), delegateObject: delegateObject, additionalData: additionalData) - bottomRightLabel.setWithJSON(json?.optionalDictionaryForKey("bottomRightLabel"), delegateObject: delegateObject, additionalData: additionalData) - - topLabelToMoleculeConstraint?.constant = (molecule != nil && (topLeftLabel.hasText || topRightLabel.hasText)) ? spaceAboveMolecule : 0 - bottomLabelToMoleculeConstraint?.constant = (molecule != nil && (bottomLeftLabel.hasText || bottomRightLabel.hasText)) ? spaceBelowMolecule : 0 - } - public override func setAsMolecule() { super.setAsMolecule() styleDefault() @@ -163,8 +152,7 @@ import UIKit styleDefault() spaceAboveMolecule = 6.0 spaceBelowMolecule = 6.0 - - molecule?.reset?() + (middleView as? MoleculeViewProtocol)?.reset?() } func styleDefault() { @@ -174,25 +162,27 @@ import UIKit bottomRightLabel.styleB3(true) } - public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 34 } -} -extension CornerLabels: MoleculeViewProtocol { - public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - guard let model = model as? CornerLabelsModel, - let data = try? model.encode(using: JSONEncoder()), - let json = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any] else { - return + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) + guard let model = model as? CornerLabelsModel else { return } + if middleView != nil { + (middleView as? ModelMoleculeViewProtocol)?.setWithModel(model, delegateObject, additionalData) + } else { + if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(model.molecule, delegateObject) { + addMiddleView(molecule) + } } - self.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) -// topLeftLabel.setWithModel(model.topLeftLabel, delegateObject, additionalData) -// topRightLabel.setWithModel(model.topRightLabel, delegateObject, additionalData) -// bottomLeftLabel.setWithModel(model.bottomLeftLabel, delegateObject, additionalData) -// bottomRightLabel.setWithModel(model.bottomRightLabel, delegateObject, additionalData) -// -// topLabelToMoleculeConstraint?.constant = (molecule != nil && (topLeftLabel.hasText || topRightLabel.hasText)) ? spaceAboveMolecule : 0 -// bottomLabelToMoleculeConstraint?.constant = (molecule != nil && (bottomLeftLabel.hasText || bottomRightLabel.hasText)) ? spaceBelowMolecule : 0 + + topLeftLabel.setWithModel(model.topLeftLabel, delegateObject, additionalData) + topRightLabel.setWithModel(model.topRightLabel, delegateObject, additionalData) + bottomLeftLabel.setWithModel(model.bottomLeftLabel, delegateObject, additionalData) + bottomRightLabel.setWithModel(model.bottomRightLabel, delegateObject, additionalData) + + topLabelToMoleculeConstraint?.constant = (middleView != nil && (topLeftLabel.hasText || topRightLabel.hasText)) ? spaceAboveMolecule : 0 + bottomLabelToMoleculeConstraint?.constant = (middleView != nil && (bottomLeftLabel.hasText || bottomRightLabel.hasText)) ? spaceBelowMolecule : 0 } } diff --git a/MVMCoreUI/Molecules/MoleculeContainer.swift b/MVMCoreUI/Molecules/MoleculeContainer.swift index f45ca482..e3646bcf 100644 --- a/MVMCoreUI/Molecules/MoleculeContainer.swift +++ b/MVMCoreUI/Molecules/MoleculeContainer.swift @@ -9,6 +9,11 @@ import UIKit open class MoleculeContainer: Container { + + /// Can be overriden to change how the molecule is added to the hierarchy. + public func addMolecule(_ molecule: UIView) { + addAndContain(molecule) + } override public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule) else { @@ -31,7 +36,7 @@ open class MoleculeContainer: Container { (view as? ModelMoleculeViewProtocol)?.setWithModel(casteModel.molecule, delegateObject, additionalData) } else { if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(casteModel.molecule, delegateObject) { - addAndContain(molecule) + addMolecule(molecule) } } } diff --git a/MVMCoreUI/Organisms/MoleculeStackView.swift b/MVMCoreUI/Organisms/MoleculeStackView.swift index a09ec83d..921511fc 100644 --- a/MVMCoreUI/Organisms/MoleculeStackView.swift +++ b/MVMCoreUI/Organisms/MoleculeStackView.swift @@ -223,8 +223,8 @@ open class MoleculeStackView: Container { stackItem.translatesAutoresizingMaskIntoConstraints = false let spacing = model.spacing ?? stackModel.spacing - let verticalAlignment = model.verticalAlignment ?? (stackItem.view as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() ?? (model.percentage == nil && stackModel.axis == .vertical ? .fill : (stackModel.axis == .vertical ? .leading : .center)) - let horizontalAlignment = model.horizontalAlignment ?? (stackItem.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (stackModel.axis == .vertical || model.percentage == nil ? .fill : .leading) + let verticalAlignment = model.verticalAlignment ?? (stackItem.view as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() ?? (model.percent == nil && stackModel.axis == .vertical ? .fill : (stackModel.axis == .vertical ? .leading : .center)) + let horizontalAlignment = model.horizontalAlignment ?? (stackItem.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (stackModel.axis == .vertical || model.percent == nil ? .fill : .leading) stackItem.containerHelper.alignHorizontal(horizontalAlignment) stackItem.containerHelper.alignVertical(verticalAlignment) @@ -239,7 +239,7 @@ open class MoleculeStackView: Container { } pinView(stackItem, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0) pinView(contentView, toView: stackItem, attribute: .trailing, relation: .equal, priority: .required, constant: 0) - if let percent = model.percentage { + if let percent = model.percent { stackItem.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: CGFloat(percent)/100.0).isActive = true } if lastItem { @@ -256,7 +256,7 @@ open class MoleculeStackView: Container { } pinView(stackItem, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0) pinView(contentView, toView: stackItem, attribute: .bottom, relation: .equal, priority: .required, constant: 0) - if let percent = model.percentage { + if let percent = model.percent { stackItem.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: CGFloat(percent)/100.0).isActive = true } if lastItem {