diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 4b0faceb..67b98b6b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -282,6 +282,8 @@ BBBBC87D24374A4900B0F079 /* ListThreeColumnBillChangesDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBBBC87B24374A4900B0F079 /* ListThreeColumnBillChangesDividerModel.swift */; }; BBC0C4FD24811DBC0087C44F /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBC0C4FC24811DBC0087C44F /* Tag.swift */; }; BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBC0C4FE24811DCA0087C44F /* TagModel.swift */; }; + BBF2CDB4254697C00024472A /* ListLeftVariableIconWithRightCaretAllTextLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBF2CDB3254697C00024472A /* ListLeftVariableIconWithRightCaretAllTextLinksModel.swift */; }; + BBF2CDB7254697CF0024472A /* ListLeftVariableIconWithRightCaretAllTextLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBF2CDB6254697CF0024472A /* ListLeftVariableIconWithRightCaretAllTextLinks.swift */; }; C003506123AA94CD00B6AC29 /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = C003506023AA94CD00B6AC29 /* Button.swift */; }; C07065C42395677300FBF997 /* Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07065C32395677300FBF997 /* Link.swift */; }; C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */; }; @@ -794,6 +796,8 @@ BBBBC87B24374A4900B0F079 /* ListThreeColumnBillChangesDividerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListThreeColumnBillChangesDividerModel.swift; sourceTree = ""; }; BBC0C4FC24811DBC0087C44F /* Tag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = ""; }; BBC0C4FE24811DCA0087C44F /* TagModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagModel.swift; sourceTree = ""; }; + BBF2CDB3254697C00024472A /* ListLeftVariableIconWithRightCaretAllTextLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaretAllTextLinksModel.swift; sourceTree = ""; }; + BBF2CDB6254697CF0024472A /* ListLeftVariableIconWithRightCaretAllTextLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaretAllTextLinks.swift; sourceTree = ""; }; C003506023AA94CD00B6AC29 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; C07065C32395677300FBF997 /* Link.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Link.swift; sourceTree = ""; }; C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnOrderedListModel.swift; sourceTree = ""; }; @@ -1491,6 +1495,8 @@ 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */, AA0A257724766C8A00862F64 /* ListLeftVariableIconWithRightCaretBodyTextModel.swift */, AA0A257924766CA200862F64 /* ListLeftVariableIconWithRightCaretBodyText.swift */, + BBF2CDB3254697C00024472A /* ListLeftVariableIconWithRightCaretAllTextLinksModel.swift */, + BBF2CDB6254697CF0024472A /* ListLeftVariableIconWithRightCaretAllTextLinks.swift */, 0A6682A32434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift */, 0A6682A12434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift */, AA7F32AA246C0F7900C965BA /* ListLeftVariableRadioButtonAllTextAndLinksModel.swift */, @@ -2389,6 +2395,7 @@ D2E2A99823D8D63C000B42E6 /* ActionDetailWithImageModel.swift in Sources */, D28764AC245898A400CB882D /* ThreeLayerFillMiddleTemplateModel.swift in Sources */, BBBBC87D24374A4900B0F079 /* ListThreeColumnBillChangesDividerModel.swift in Sources */, + BBF2CDB7254697CF0024472A /* ListLeftVariableIconWithRightCaretAllTextLinks.swift in Sources */, D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */, 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */, D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */, @@ -2401,6 +2408,7 @@ D2CAC7D3251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift in Sources */, AA07EA932510A451009A2AE3 /* Star.swift in Sources */, D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */, + BBF2CDB4254697C00024472A /* ListLeftVariableIconWithRightCaretAllTextLinksModel.swift in Sources */, D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */, D28BA74D248589C800B75CB8 /* TabPageModelProtocol.swift in Sources */, 014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index 8a5b737a..036d4070 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -171,6 +171,7 @@ import Foundation // MARK:- Designed List Items MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableIconWithRightCaret.self, viewModelClass: ListLeftVariableIconWithRightCaretModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableIconWithRightCaretBodyText.self, viewModelClass: ListLeftVariableIconWithRightCaretBodyTextModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableIconWithRightCaretAllTextLinks.self, viewModelClass: ListLeftVariableIconWithRightCaretAllTextLinksModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableCheckboxAllTextAndLinks.self, viewModelClass: ListLeftVariableCheckboxAllTextAndLinksModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableRadioButtonAndPaymentMethod.self, viewModelClass: ListLeftVariableRadioButtonAndPaymentMethodModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableRadioButtonBodyText.self, viewModelClass: ListLeftVariableRadioButtonBodyTextModel.self) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretAllTextLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretAllTextLinks.swift new file mode 100644 index 00000000..29159ddc --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretAllTextLinks.swift @@ -0,0 +1,137 @@ +// +// ListLeftVariableIconWithRightCaretAllTextLinks.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 26/10/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +@objcMembers open class ListLeftVariableIconWithRightCaretAllTextLinks: TableViewCell { + //-------------------------------------------------- + // MARK: - Outlets + //-------------------------------------------------- + + public let leftImage = LoadImageView() + public let eyebrowHeadlineBodyLink = EyebrowHeadlineBodyLink() + public let rightLabel = Label(fontStyle: .RegularBodySmall) + public let rightLabelStackItem: StackItem + public var stack: Stack + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + rightLabelStackItem = StackItem(andContain: rightLabel) + let stackItems = [StackItem(andContain: leftImage), StackItem(andContain: eyebrowHeadlineBodyLink), rightLabelStackItem] + let stackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .fill), StackItemModel(horizontalAlignment: .fill), StackItemModel(horizontalAlignment: .fill)], axis: .horizontal) + stack = Stack(with: stackModel, stackItems: stackItems) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open override func alignAccessoryToHero() -> CGPoint? { + // Ensures that the right label is centered vertically with headline. + let heroCenter = super.alignAccessoryToHero() + if let heroCenter = heroCenter { + let convertedPoint = stack.convert(heroCenter, from: self) + rightLabelStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - stack.bounds.midY + } + return heroCenter + } + + //----------------------------------------------------- + // MARK: - View Lifecycle + //-------------------------------------------------- + + override open func setupView() { + super.setupView() + + leftImage.addSizeConstraintsForAspectRatio = true + leftImage.contentMode = .scaleAspectFit + rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) + rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal) + rightLabel.numberOfLines = 1 + addMolecule(stack) + stack.restack() + } + + //-------------------------------------------------- + // MARK: - Molecule + //--------------------------------------------------- + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.set(with: model, delegateObject, additionalData) + + guard let model = model as? ListLeftVariableIconWithRightCaretAllTextLinksModel else { return } + + leftImage.set(with: model.image, delegateObject, additionalData) + eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData) + rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + updateAccessibilityLabel() + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 90 + } + + open override func reset() { + super.reset() + rightLabel.setFontStyle(.RegularBodySmall) + } + + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + + + func getAccessibilityMessage() -> String? { + var message: String = "" + + if let leftImageLabel = leftImage.imageView.accessibilityLabel { + message += leftImageLabel + ", " + } + if let rightLabel = rightLabel.text { + message += rightLabel + } + if let label = eyebrowHeadlineBodyLink.getAccessibilityMessage() { + message += label + } + + return message + } + + func updateAccessibilityLabel() { + + let linkShowing = eyebrowHeadlineBodyLink.link.titleLabel?.text?.count ?? 0 > 0 + accessibilityTraits = .button + + if !linkShowing && accessoryView == nil { + // Make whole cell focusable if one action + isAccessibilityElement = true + accessibilityLabel = getAccessibilityMessage() + } else { + // Make buttons focusable. + isAccessibilityElement = false + var elements: [Any] = [] + + if let accessoryView = accessoryView { + accessoryView.accessibilityLabel = eyebrowHeadlineBodyLink.getAccessibilityMessage() + elements.append(accessoryView) + } else { + eyebrowHeadlineBodyLink.link.accessibilityLabel = eyebrowHeadlineBodyLink.link.titleLabel?.text + } + + elements.append(link) + + if linkShowing { + elements.append(eyebrowHeadlineBodyLink.link) + } + + accessibilityElements = elements + } + } +} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretAllTextLinksModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretAllTextLinksModel.swift new file mode 100644 index 00000000..f83d0c6f --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretAllTextLinksModel.swift @@ -0,0 +1,74 @@ +// +// ListLeftVariableIconWithRightCaretAllTextLinksModel.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 26/10/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +public class ListLeftVariableIconWithRightCaretAllTextLinksModel: ListItemModel, MoleculeModelProtocol { + //----------------------------------------------------- + // MARK: - Properties + //----------------------------------------------------- + + public static var identifier: String = "listLVImgRCAll" + public var image: ImageViewModel + public var eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel + public var rightLabel: LabelModel + + //----------------------------------------------------- + // MARK: - Methods + //----------------------------------------------------- + + override public func setDefaults() { + super.setDefaults() + if image.width == nil, image.height == nil { + image.width = 30 + image.height = 30 + } + eyebrowHeadlineBodyLink.headline?.hero = 0 + } + + //----------------------------------------------------- + // MARK: - Initializers + //----------------------------------------------------- + + public init(image: ImageViewModel, eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel, rightLabel: LabelModel) { + self.image = image + self.eyebrowHeadlineBodyLink = eyebrowHeadlineBodyLink + self.rightLabel = rightLabel + super.init() + } + + //----------------------------------------------------- + // MARK: - Keys + //----------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case moleculeName + case image + case eyebrowHeadlineBodyLink + case rightLabel + } + + //----------------------------------------------------- + // MARK: - Codec + //----------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + image = try typeContainer.decode(ImageViewModel.self, forKey: .image) + eyebrowHeadlineBodyLink = try typeContainer.decode(EyebrowHeadlineBodyLinkModel.self, forKey: .eyebrowHeadlineBodyLink) + rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) + 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.encode(image, forKey: .image) + try container.encode(eyebrowHeadlineBodyLink, forKey: .eyebrowHeadlineBodyLink) + try container.encode(rightLabel, forKey: .rightLabel) + } +}