diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 368984ec..e98e8f7e 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -156,7 +156,7 @@ 9432A79F23DB47BA00719041 /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */; }; 943784F5236B77BB006A1E82 /* Wheel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* Wheel.swift */; }; 943784F6236B77BB006A1E82 /* WheelAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* WheelAnimationHandler.swift */; }; - 943820842432382400B43AF3 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943820832432382400B43AF3 /* WebView.swift */; }; + 943820842432382400B43AF3 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943820832432382400B43AF3 /* WebView.swift */; }; 94382086243238D100B43AF3 /* WebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94382085243238D100B43AF3 /* WebViewModel.swift */; }; 9445890C2385BCE300DE9FD4 /* ProgressBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */; }; 9445890E2385C3F800DE9FD4 /* MultiProgressModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9445890D2385C3F800DE9FD4 /* MultiProgressModel.swift */; }; @@ -204,6 +204,8 @@ AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C10724346F4B00151545 /* RadioSwatches.swift */; }; AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C109243496DD00151545 /* RadioSwatch.swift */; }; AAC6F167243332E400F295C1 /* RadioSwatchesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */; }; + BB1D17E0244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */; }; + BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */; }; BB2C968F24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */; }; BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2C969124330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift */; }; BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */; }; @@ -645,6 +647,8 @@ AAB9C10724346F4B00151545 /* RadioSwatches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatches.swift; sourceTree = ""; }; AAB9C109243496DD00151545 /* RadioSwatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = ""; }; AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchesModel.swift; sourceTree = ""; }; + BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMediumModel.swift; sourceTree = ""; }; + BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMedium.swift; sourceTree = ""; }; BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinksModel.swift; sourceTree = ""; }; BB2C969124330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinks.swift; sourceTree = ""; }; BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsectionModel.swift; sourceTree = ""; }; @@ -1168,6 +1172,15 @@ path = FourColumn; sourceTree = ""; }; + D20FFFB42451E32100A31DA2 /* Device */ = { + isa = PBXGroup; + children = ( + BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */, + BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */, + ); + path = Device; + sourceTree = ""; + }; D213347423842FE3008E41B3 /* Controllers */ = { isa = PBXGroup; children = ( @@ -1366,6 +1379,7 @@ D22B38EA23F4E08B00490EF6 /* List */ = { isa = PBXGroup; children = ( + D20FFFB42451E32100A31DA2 /* Device */, 52267A0523FFE0A900906CBA /* OneColumn */, D22D8396241FDE4700D3DF69 /* TwoColumn */, 8DD1E36C243B3CD900D8F2DF /* ThreeColumn */, @@ -2164,6 +2178,7 @@ D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */, D29DF12E21E6851E003B2FB9 /* MVMCoreUITopAlertView.m in Sources */, AA1EC59724373985003D6F50 /* ListThreeColumnSpeedTestDividerModel.swift in Sources */, + BB1D17E0244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift in Sources */, D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */, D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */, 014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */, @@ -2214,7 +2229,7 @@ D29E28D823D21AB800ACEA85 /* StringAndMoleculeView.swift in Sources */, 01EB369023609801006832FA /* MoleculeListItemModel.swift in Sources */, D28A838323CCBD3F00DFE4FC /* WheelModel.swift in Sources */, - EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */, + EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */, D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */, DBEFFA04225A829700230692 /* Label.swift in Sources */, D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, @@ -2411,6 +2426,7 @@ D21B7F73243BAC6800051ABF /* CollectionItemModelProtocol.swift in Sources */, C7192E7D23C301750050C2A0 /* HeadLineBodyCaretLinkImage.swift in Sources */, D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, + BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, 0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */, 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index 7c57fd40..464238a7 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -167,6 +167,10 @@ import Foundation // Designed Headers MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2NoButtonsBodyText.self, viewModelClass: HeadersH2NoButtonsBodyTextModel.self) + + + // Device Items + MoleculeObjectMapping.shared()?.register(viewClass: ListDeviceComplexButtonMedium.self, viewModelClass: ListDeviceComplexButtonMediumModel.self) // TODO: Need View try? ModelRegistry.register(TabsModel.self) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift new file mode 100644 index 00000000..f8ab918d --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift @@ -0,0 +1,79 @@ +// +// ListDeviceComplexButtonMedium.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 21/04/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +@objcMembers open class ListDeviceComplexButtonMedium: TableViewCell { + + public var verticalStack: Stack + public let eyebrow = Label.createLabelRegularMicro(true) + public let headline = Label.createLabelBoldTitleMedium(true) + public let body = Label.createLabelRegularBodySmall(true) + public let body2 = Label.createLabelRegularBodySmall(true) + public let button = PillButton(frame: .zero) + public let rightImageView = MFLoadImageView() + public var stack: Stack + + // MARK: - Initializers + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + rightImageView.addSizeConstraintsForAspectRatio = true + rightImageView.heightAnchor.constraint(equalToConstant: 116.0).isActive = true + rightImageView.widthAnchor.constraint(equalToConstant: 116.0).isActive = true + verticalStack = Stack.createStack(with: [(view: eyebrow, model: StackItemModel(horizontalAlignment: .leading)), + (view: headline, model: StackItemModel(horizontalAlignment: .leading)), + (view: body, model: StackItemModel(horizontalAlignment: .leading)), + (view: body2, model: StackItemModel(horizontalAlignment: .leading)), + (view: button, model: StackItemModel(spacing:16, horizontalAlignment: .leading))], + axis: .vertical, spacing: 0) + stack = Stack.createStack(with: [(view: verticalStack, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .leading)), + (view: rightImageView, model: StackItemModel(horizontalAlignment: .fill, verticalAlignment: .center))], + axis: .horizontal) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - MFViewProtocol + open override func setupView() { + super.setupView() + addMolecule(stack) + stack.restack() + verticalStack.restack() + } + + // MARK: - ModelMoleculeViewProtocol + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListDeviceComplexButtonMediumModel else { return } + verticalStack.updateContainedMolecules(with: [model.eyebrow, + model.headline, + model.body, + model.body2, + model.button], + delegateObject, additionalData) + rightImageView.set(with: model.image, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 120 + } + + public func setDefault() { + eyebrow.styleRegularMicro(true) + headline.styleBoldTitleMedium(true) + body.styleRegularBodySmall(true) + body2.styleRegularBodySmall(true) + eyebrow.textColor = .mvmCoolGray6 + } + + open override func reset() { + super.reset() + setDefault() + } +} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift new file mode 100644 index 00000000..7f676795 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift @@ -0,0 +1,68 @@ +// +// ListDeviceComplexButtonMediumModel.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 21/04/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +public class ListDeviceComplexButtonMediumModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "listDvcBtnM" + public var eyebrow: LabelModel? + public var headline: LabelModel? + public var body: LabelModel? + public var body2: LabelModel? + public var button: ButtonModel + public var image: ImageViewModel + + public init(eyebrow: LabelModel, headline:LabelModel, body: LabelModel, body2: LabelModel, button: ButtonModel, image: ImageViewModel) { + self.eyebrow = eyebrow + self.headline = headline + self.body = body + self.body2 = body2 + self.button = button + self.image = image + super.init() + } + + /// Defaults to set + override public func setDefaults() { + super.setDefaults() + button.size = .tiny + button.style = .secondary + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case eyebrow + case headline + case body + case body2 + case button + case image + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow) + headline = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .headline) + body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body) + body2 = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body2) + button = try typeContainer.decode(ButtonModel.self, forKey: .button) + image = try typeContainer.decode(ImageViewModel.self, forKey: .image) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encodeIfPresent(eyebrow, forKey: .eyebrow) + try container.encodeIfPresent(headline, forKey: .headline) + try container.encodeIfPresent(body, forKey: .body) + try container.encodeIfPresent(body2, forKey: .body2) + try container.encode(button, forKey: .button) + try container.encode(image, forKey: .image) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift index 1ea1a4a9..ad74039a 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift @@ -40,24 +40,18 @@ import Foundation override open func setupView() { super.setupView() addMolecule(stack) + stack.restack() } open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?){ super.set(with: model, delegateObject, additionalData) guard let model = model as? ListOneColumnFullWidthTextAllTextAndLinksModel else { return } - eyebrow.setOptional(with: model.eyebrow, delegateObject, additionalData) - headline.setOptional(with: model.headline, delegateObject, additionalData) - subHeadline.setOptional(with: model.subHeadline, delegateObject, additionalData) - body.setOptional(with: model.body, delegateObject, additionalData) - link.setOptional(with: model.link, delegateObject, additionalData) - - // Hide labels if neeeded. - stack.stackModel?.molecules[0].gone = !eyebrow.hasText - stack.stackModel?.molecules[1].gone = !headline.hasText - stack.stackModel?.molecules[2].gone = !subHeadline.hasText - stack.stackModel?.molecules[3].gone = !body.hasText - stack.stackModel?.molecules[4].gone = (link.titleLabel?.text?.count ?? 0) == 0 - stack.restack() + stack.updateContainedMolecules(with: [model.eyebrow, + model.headline, + model.subHeadline, + model.body, + model.link], + delegateObject, additionalData) } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift index 82f83530..dd04140b 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift @@ -33,6 +33,7 @@ import UIKit stack.stackModel?.spacing = 0 addSubview(stack) NSLayoutConstraint.constraintPinSubview(toSuperview: stack) + stack.restack() } open override func updateView(_ size: CGFloat) { @@ -58,18 +59,11 @@ import UIKit open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) - - eyebrow.setOptional(with: castModel?.eyebrow, delegateObject, additionalData) - headline.setOptional(with: castModel?.headline, delegateObject, additionalData) - body.setOptional(with: castModel?.body, delegateObject, additionalData) - link.setOptional(with: castModel?.link, delegateObject, additionalData) - - // Hide labels if neeeded. - stack.stackModel?.molecules[0].gone = !eyebrow.hasText - stack.stackModel?.molecules[1].gone = !headline.hasText - stack.stackModel?.molecules[2].gone = !body.hasText - stack.stackModel?.molecules[3].gone = (link.titleLabel?.text?.count ?? 0) == 0 - stack.restack() + stack.updateContainedMolecules(with: [castModel?.eyebrow, + castModel?.headline, + castModel?.body, + castModel?.link], + delegateObject, additionalData) } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Organisms/Stack.swift b/MVMCoreUI/Atomic/Organisms/Stack.swift index f539cf8b..ad961586 100644 --- a/MVMCoreUI/Atomic/Organisms/Stack.swift +++ b/MVMCoreUI/Atomic/Organisms/Stack.swift @@ -62,6 +62,32 @@ open class Stack: Container where T: (StackModelProtocol & MoleculeModelProto } } + /// A convenience function for when the stackItems are containers and we want to update them based on the contained molecules models. If model is nil, stackItem is set to gone. Restacks if necessary. + open func updateContainedMolecules(with models: [MoleculeModelProtocol?], _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + guard var stackModel = stackModel else { return } + var needsRestack = false + for (index, item) in stackItems.enumerated() { + guard let container = item as? UIView & ContainerProtocol, + let contained = container.view as? MoleculeViewProtocol else { + continue + } + if let model = models[index] { + contained.set(with: model, delegateObject, additionalData) + if stackModel.molecules[index].gone { + stackModel.molecules[index].gone = false + needsRestack = true + } + } else if !stackModel.molecules[index].gone { + stackModel.molecules[index].gone = true + needsRestack = true + } + } + + if needsRestack { + restack() + } + } + //-------------------------------------------------- // MARK: - Initializers //--------------------------------------------------