From 77dbd5d473097aa3fe4cc0b382e8fffcf6e94e2d Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 3 Jun 2020 16:58:47 -0400 Subject: [PATCH] designed component accessibility --- .../Headers/HeadersH2Buttons.swift | 85 ++++++++++++- .../Headers/HeadersH2ButtonsModel.swift | 9 ++ .../Headers/HeadersH2NoButtonsBodyText.swift | 30 ++++- .../HeadersH2NoButtonsBodyTextModel.swift | 5 + .../Headers/HeadersH2TinyButton.swift | 56 +++++++-- .../Headers/HeadersH2TinyButtonModel.swift | 8 ++ .../ListDeviceComplexButtonMedium.swift | 68 +++++++++-- .../ListDeviceComplexButtonMediumModel.swift | 23 +++- .../Device/ListDeviceComplexButtonSmall.swift | 72 +++++++++-- .../ListDeviceComplexButtonSmallModel.swift | 23 +++- .../Device/ListDeviceComplexLinkMedium.swift | 112 +++++++++++++++++- .../ListDeviceComplexLinkMediumModel.swift | 18 +++ .../Device/ListDeviceComplexLinkSmall.swift | 112 +++++++++++++++++- .../ListDeviceComplexLinkSmallModel.swift | 18 +++ .../ListFourColumnDataUsageListItem.swift | 53 +++++++-- ...ListFourColumnDataUsageListItemModel.swift | 17 +++ ...ftVariableIconWithRightCaretBodyText.swift | 5 + ...tVariableNumberedListAllTextAndLinks.swift | 4 + ...ftVariableRadioButtonAllTextAndLinks.swift | 10 +- ...tVariableRadioButtonAndPaymentMethod.swift | 4 + .../ListLeftVariableRadioButtonBodyText.swift | 4 + ...neColumnFullWidthTextAllTextAndLinks.swift | 4 + ...htVariablePriceChangeAllTextAndLinks.swift | 2 - .../ListThreeColumnDataUsage.swift | 75 +++++++++--- .../ListThreeColumnDataUsageModel.swift | 18 ++- .../ListThreeColumnInternationalData.swift | 44 ++++++- ...istThreeColumnInternationalDataModel.swift | 17 +++ .../ListFourColumnDataUsageDivider.swift | 28 +++++ ...ColumnFullWidthTextDividerSubsection.swift | 22 ++++ ...ColumnTextWithWhitespaceDividerShort.swift | 22 ++++ ...eColumnTextWithWhitespaceDividerTall.swift | 22 ++++ .../ListThreeColumnBillChangesDivider.swift | 26 ++++ .../ListThreeColumnDataUsageDivider.swift | 26 ++++ ...tThreeColumnInternationalDataDivider.swift | 26 ++++ .../ListThreeColumnPlanDataDivider.swift | 38 ++++++ .../ListThreeColumnSpeedTestDivider.swift | 33 +++++- .../ListTwoColumnSubsectionDivider.swift | 22 ++++ .../TwoLinkView.swift | 25 ++++ 38 files changed, 1105 insertions(+), 81 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift index 57e62d24..0d8e359d 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift @@ -8,17 +8,20 @@ import Foundation + @objcMembers open class HeadersH2Buttons: HeaderView { //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- - public let headlineBody = HeadlineBody(frame: .zero) - public let buttons = TwoButtonView(frame: .zero) + + public let headlineBody = HeadlineBody() + public let buttons = TwoButtonView() public let stack: Stack //------------------------------------------------------- // MARK: - Initializers //------------------------------------------------------- + public override init(frame: CGRect) { stack = Stack.createStack(with: [headlineBody, buttons], spacing: PaddingDefaultVerticalSpacing3) super.init(frame: frame) @@ -29,23 +32,29 @@ import Foundation } //------------------------------------------------------- - // MARK: - View Lifecycle + // MARK: - Lifecycle //------------------------------------------------------- + open override func setupView() { super.setupView() headlineBody.stylePageHeader() addMolecule(stack) stack.restack() + updateAccessibilityLabel() } //---------------------------------------------------- // MARK: - Molecule //------------------------------------------------------ - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? HeadersH2ButtonsModel else { return } + headlineBody.set(with: model.headlineBody, delegateObject, additionalData) buttons.set(with: model.buttons, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -56,4 +65,72 @@ import Foundation super.reset() headlineBody.stylePageHeader() } + + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let headlineText = headlineBody.headlineLabel.text, !headlineText.isEmpty { + message += headlineText + ", " + } + + if let messageText = headlineBody.messageLabel.text, !messageText.isEmpty { + message += messageText + ", " + } + + let secondaryButtonIsDisplayed = !buttons.secondaryButton.isHidden + let primaryButtonIsDisplayed = !buttons.primaryButton.isHidden + + // Both links are displayed + if secondaryButtonIsDisplayed && primaryButtonIsDisplayed { + isAccessibilityElement = false + var views = [UIView]() + + if let headlineText = headlineBody.headlineLabel.text, !headlineText.isEmpty { + views.append(headlineBody.headlineLabel) + } + + if let messageText = headlineBody.messageLabel.text, !messageText.isEmpty { + views.append(headlineBody.messageLabel) + } + + views.append(buttons.secondaryButton) + views.append(buttons.primaryButton) + + accessibilityElements = views + return + + } else if secondaryButtonIsDisplayed { + accessibilityHint = buttons.secondaryButton.accessibilityHint + accessibilityTraits = buttons.secondaryButton.accessibilityTraits + message += buttons.secondaryButton.accessibilityLabel ?? "" + + } else if primaryButtonIsDisplayed { + accessibilityHint = buttons.primaryButton.accessibilityHint + accessibilityTraits = buttons.primaryButton.accessibilityTraits + message += buttons.primaryButton.accessibilityLabel ?? "" + + } + + isAccessibilityElement = true + accessibilityLabel = message + } + + open override func accessibilityActivate() -> Bool { + + if isAccessibilityElement { + if !buttons.secondaryButton.isHidden { + return buttons.secondaryButton.accessibilityActivate() + + } else if !buttons.primaryButton.isHidden { + return buttons.primaryButton.accessibilityActivate() + } + } + + return false + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift index afc57f2e..3cb09a0f 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift @@ -8,10 +8,12 @@ import Foundation + public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- + public static var identifier: String = "headerH2Btns" public var headlineBody: HeadlineBodyModel public var buttons: TwoButtonViewModel @@ -19,12 +21,17 @@ public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- + public init(headlineBody: HeadlineBodyModel, buttons: TwoButtonViewModel) { self.headlineBody = headlineBody self.buttons = buttons super.init() } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + public override func setDefaults() { super.setDefaults() topPadding = PaddingDefaultVerticalSpacing3 @@ -34,6 +41,7 @@ public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case headlineBody @@ -43,6 +51,7 @@ public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift index 8826a239..133b25ce 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift @@ -8,29 +8,36 @@ import Foundation + @objcMembers open class HeadersH2NoButtonsBodyText: HeaderView { //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- - let headlineBody = HeadlineBody(frame: .zero) + public let headlineBody = HeadlineBody() //------------------------------------------------------- // MARK: - View Lifecycle //------------------------------------------------------- + open override func setupView() { super.setupView() headlineBody.stylePageHeader() addMolecule(headlineBody) + isAccessibilityElement = true + updateAccessibilityLabel() } //---------------------------------------------------- // MARK: - Molecule //------------------------------------------------------ - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? HeadersH2NoButtonsBodyTextModel else { return } + headlineBody.set(with: model.headlineBody, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -41,4 +48,23 @@ import Foundation super.reset() headlineBody.stylePageHeader() } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let headlineLabel = headlineBody.headlineLabel.text { + message += headlineLabel + ", " + } + + if let messageLabel = headlineBody.messageLabel.text { + message += messageLabel + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyTextModel.swift index 816db00d..a6cfc0ce 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyTextModel.swift @@ -8,16 +8,19 @@ import Foundation + public class HeadersH2NoButtonsBodyTextModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- + public static var identifier: String = "headerH2" public var headlineBody: HeadlineBodyModel //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- + public init(headlineBody: HeadlineBodyModel) { self.headlineBody = headlineBody super.init() @@ -32,6 +35,7 @@ public class HeadersH2NoButtonsBodyTextModel: HeaderModel, MoleculeModelProtocol //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case headlineBody @@ -40,6 +44,7 @@ public class HeadersH2NoButtonsBodyTextModel: HeaderModel, MoleculeModelProtocol //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButton.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButton.swift index 788a6a89..5b6d2ea8 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButton.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButton.swift @@ -8,19 +8,24 @@ import Foundation + @objcMembers open class HeadersH2TinyButton: HeaderView { //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- - public let headlineBody = HeadlineBody(frame: .zero) - public let button = PillButton(frame: .zero) + + public let headlineBody = HeadlineBody() + public let button = PillButton() public let stack: Stack - + //------------------------------------------------------- // MARK: - Initializers //------------------------------------------------------- + public override init(frame: CGRect) { - stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .fill)), (view: button, model: StackItemModel(spacing: spacingBetwenHeadlineBodyAndButton, horizontalAlignment: .leading))], axis: .vertical) + stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .fill)), + (view: button, model: StackItemModel(spacing: spacingBetwenHeadlineBodyAndButton, horizontalAlignment: .leading))], + axis: .vertical) super.init(frame: frame) } @@ -31,26 +36,36 @@ import Foundation //------------------------------------------------------ // MARK: - Constants //------------------------------------------------------ + let spacingBetwenHeadlineBodyAndButton: CGFloat = 16.0 //------------------------------------------------------- - // MARK: - View Lifecycle + // MARK: - Lifecycle //------------------------------------------------------- + open override func setupView() { super.setupView() headlineBody.stylePageHeader() addMolecule(stack) stack.restack() + isAccessibilityElement = true + accessibilityHint = button.accessibilityHint + accessibilityTraits = button.accessibilityTraits + updateAccessibilityLabel() } //---------------------------------------------------- // MARK: - Molecule - //------------------------------------------------------ - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + //---------------------------------------------------- + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? HeadersH2TinyButtonModel else { return } + headlineBody.set(with: model.headlineBody, delegateObject, additionalData) button.set(with: model.button, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -61,4 +76,31 @@ import Foundation super.reset() headlineBody.stylePageHeader() } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let headlineLabel = headlineBody.headlineLabel.text, !headlineLabel.isEmpty { + message += headlineLabel + ", " + } + + if let bodyLabel = headlineBody.messageLabel.text, !bodyLabel.isEmpty { + message += bodyLabel + ", " + } + + if let buttonLabel = button.accessibilityLabel { + message += buttonLabel + } + + accessibilityLabel = message + } + + open override func accessibilityActivate() -> Bool { + return button.accessibilityActivate() + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButtonModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButtonModel.swift index 522c4910..55c2c6e4 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButtonModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButtonModel.swift @@ -8,6 +8,7 @@ import Foundation + public class HeadersH2TinyButtonModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties @@ -20,12 +21,17 @@ public class HeadersH2TinyButtonModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- + public init(headlineBody: HeadlineBodyModel, button: ButtonModel) { self.headlineBody = headlineBody self.button = button super.init() } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + public override func setDefaults() { super.setDefaults() topPadding = PaddingDefaultVerticalSpacing3 @@ -37,6 +43,7 @@ public class HeadersH2TinyButtonModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case headlineBody @@ -46,6 +53,7 @@ public class HeadersH2TinyButtonModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift index e6e226cb..92ae4bad 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift @@ -7,18 +7,26 @@ // import Foundation + + @objcMembers open class ListDeviceComplexButtonMedium: TableViewCell { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- 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 button = PillButton() public let rightImageView = LoadImageView() public var stack: Stack + //-------------------------------------------------- // MARK: - Initializers + //-------------------------------------------------- + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { rightImageView.addSizeConstraintsForAspectRatio = true rightImageView.imageView.contentMode = .scaleAspectFit @@ -40,26 +48,35 @@ import Foundation fatalError("init(coder:) has not been implemented") } - // MARK: - MFViewProtocol + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func setupView() { super.setupView() rightImageView.shouldNotifyDelegateOnUpdate = false addMolecule(stack) stack.restack() verticalStack.restack() + isAccessibilityElement = true + accessibilityTraits = button.accessibilityTraits + accessibilityHint = button.accessibilityHint + updateAccessibilityLabel() } + //-------------------------------------------------- // MARK: - ModelMoleculeViewProtocol - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + //-------------------------------------------------- + + 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], + + verticalStack.updateContainedMolecules(with: [model.eyebrow, model.headline, model.body, model.body2, model.button], delegateObject, additionalData) rightImageView.set(with: model.image, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -78,4 +95,39 @@ import Foundation super.reset() setDefault() } + + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty { + message += eyebrowText + ", " + } + + if let headlineText = headline.text, !headlineText.isEmpty { + message += headlineText + ", " + } + + if let bodyText = body.text, !bodyText.isEmpty { + message += bodyText + ", " + } + + if let body2Text = body2.text, !body2Text.isEmpty { + message += body2Text + ", " + } + + if let rightImageViewText = rightImageView.accessibilityLabel, !rightImageViewText.isEmpty { + message += rightImageViewText + } + + accessibilityLabel = message + } + + open override func accessibilityActivate() -> Bool { + return button.accessibilityActivate() + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift index 7f676795..88f7fe97 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift @@ -7,7 +7,13 @@ // import Foundation + + public class ListDeviceComplexButtonMediumModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "listDvcBtnM" public var eyebrow: LabelModel? public var headline: LabelModel? @@ -16,6 +22,10 @@ public class ListDeviceComplexButtonMediumModel: ListItemModel, MoleculeModelPro public var button: ButtonModel public var image: ImageViewModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(eyebrow: LabelModel, headline:LabelModel, body: LabelModel, body2: LabelModel, button: ButtonModel, image: ImageViewModel) { self.eyebrow = eyebrow self.headline = headline @@ -26,13 +36,20 @@ public class ListDeviceComplexButtonMediumModel: ListItemModel, MoleculeModelPro super.init() } - /// Defaults to set + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + override public func setDefaults() { super.setDefaults() button.size = .tiny button.style = .secondary } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case eyebrow @@ -43,6 +60,10 @@ public class ListDeviceComplexButtonMediumModel: ListItemModel, MoleculeModelPro case image } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmall.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmall.swift index e8436620..6a64f932 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmall.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmall.swift @@ -7,23 +7,31 @@ // import Foundation + + @objcMembers open class ListDeviceComplexButtonSmall: TableViewCell { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- 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 button = PillButton() public let rightImageView = LoadImageView() public var stack: Stack + //-------------------------------------------------- // MARK: - Initializers + //-------------------------------------------------- + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { rightImageView.addSizeConstraintsForAspectRatio = true rightImageView.imageView.contentMode = .scaleAspectFit - rightImageView.heightAnchor.constraint(equalToConstant: 71.0).isActive = true - rightImageView.widthAnchor.constraint(equalToConstant: 71.0).isActive = true + rightImageView.heightAnchor.constraint(equalToConstant: 71).isActive = true + rightImageView.widthAnchor.constraint(equalToConstant: 71).isActive = true verticalStack = Stack.createStack(with: [(view: eyebrow, model: StackItemModel(horizontalAlignment: .leading)), (view: headline, model: StackItemModel(horizontalAlignment: .leading)), (view: body, model: StackItemModel(horizontalAlignment: .leading)), @@ -40,26 +48,35 @@ import Foundation fatalError("init(coder:) has not been implemented") } - // MARK: - MFViewProtocol + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func setupView() { super.setupView() rightImageView.shouldNotifyDelegateOnUpdate = false addMolecule(stack) stack.restack() verticalStack.restack() + isAccessibilityElement = true + accessibilityTraits = button.accessibilityTraits + accessibilityHint = button.accessibilityHint + updateAccessibilityLabel() } + //-------------------------------------------------- // MARK: - ModelMoleculeViewProtocol - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + //-------------------------------------------------- + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListDeviceComplexButtonSmallModel else { return } - verticalStack.updateContainedMolecules(with: [model.eyebrow, - model.headline, - model.body, - model.body2, - model.button], + + verticalStack.updateContainedMolecules(with: [model.eyebrow, model.headline, model.body, model.body2, model.button], delegateObject, additionalData) rightImageView.set(with: model.image, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -78,4 +95,39 @@ import Foundation super.reset() setDefault() } + + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty { + message += eyebrowText + ", " + } + + if let headlineText = headline.text, !headlineText.isEmpty { + message += headlineText + ", " + } + + if let bodyText = body.text, !bodyText.isEmpty { + message += bodyText + ", " + } + + if let body2Text = body2.text, !body2Text.isEmpty { + message += body2Text + ", " + } + + if let rightImageViewText = rightImageView.accessibilityLabel, !rightImageViewText.isEmpty { + message += rightImageViewText + } + + accessibilityLabel = message + } + + open override func accessibilityActivate() -> Bool { + return button.accessibilityActivate() + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmallModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmallModel.swift index 25de6eab..13be8c03 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmallModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmallModel.swift @@ -7,7 +7,13 @@ // import Foundation + + public class ListDeviceComplexButtonSmallModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "listDvcBtnS" public var eyebrow: LabelModel? public var headline: LabelModel? @@ -16,6 +22,10 @@ public class ListDeviceComplexButtonSmallModel: ListItemModel, MoleculeModelProt public var button: ButtonModel public var image: ImageViewModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(eyebrow: LabelModel, headline:LabelModel, body: LabelModel, body2: LabelModel, button: ButtonModel, image: ImageViewModel) { self.eyebrow = eyebrow self.headline = headline @@ -26,13 +36,20 @@ public class ListDeviceComplexButtonSmallModel: ListItemModel, MoleculeModelProt super.init() } - /// Defaults to set + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + override public func setDefaults() { super.setDefaults() button.size = .tiny button.style = .secondary } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case eyebrow @@ -43,6 +60,10 @@ public class ListDeviceComplexButtonSmallModel: ListItemModel, MoleculeModelProt case image } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMedium.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMedium.swift index 573335c0..ed8af1ba 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMedium.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMedium.swift @@ -7,11 +7,13 @@ // import Foundation + + @objcMembers open class ListDeviceComplexLinkMedium: TableViewCell { - //----------------------------------------------------- // MARK: - Outlets //----------------------------------------------------- + public let eyebrow = Label.createLabelRegularMicro(true) public let headline = Label.createLabelBoldTitleMedium(true) public let body = Label.createLabelRegularBodySmall(true) @@ -20,16 +22,22 @@ import Foundation public let rightImage = LoadImageView() let verticalStack: Stack public let stack: Stack - + //------------------------------------------------------ // MARK: - Initializers //------------------------------------------------------ + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { rightImage.addSizeConstraintsForAspectRatio = true rightImage.imageView.contentMode = .scaleAspectFit rightImage.heightAnchor.constraint(equalToConstant: 116.0).isActive = true rightImage.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: twoLinkView, model: StackItemModel(spacing: 16, horizontalAlignment: .leading))], axis: .vertical, spacing: 0) + 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: twoLinkView, model: StackItemModel(spacing: 16, horizontalAlignment: .leading))], + axis: .vertical, spacing: 0) stack = Stack.createStack(with: [(view: verticalStack, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .leading)), (view: rightImage, model: StackItemModel(verticalAlignment: .center))], @@ -42,24 +50,31 @@ import Foundation } //----------------------------------------------------- - // MARK: - View Lifecycle + // MARK: - Lifecycle //----------------------------------------------------- + open override func setupView() { super.setupView() + rightImage.shouldNotifyDelegateOnUpdate = false addMolecule(stack) stack.restack() verticalStack.restack() + updateAccessibilityLabel() } //------------------------------------------------------ // MARK: - Molecule //------------------------------------------------------ - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListDeviceComplexLinkMediumModel else { return } + verticalStack.updateContainedMolecules(with: [model.eyebrow, model.headline, model.body, model.body2, model.twoLinkView], delegateObject, additionalData) rightImage.set(with: model.image, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -74,4 +89,91 @@ import Foundation body2.styleRegularBodySmall(true) eyebrow.textColor = .mvmCoolGray6 } + + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty { + message += eyebrowText + ", " + } + + if let headlineText = headline.text, !headlineText.isEmpty { + message += headlineText + ", " + } + + if let bodyText = body.text, !bodyText.isEmpty { + message += bodyText + ", " + } + + if let body2Text = body2.text, !body2Text.isEmpty { + message += body2Text + ", " + } + + if let rightImageLabel = rightImage.accessibilityLabel { + message += rightImageLabel + } + + let leftLinkIsDisplayed = !twoLinkView.leftLink.isHidden + let rightLinkIsDisplayed = !twoLinkView.rightLink.isHidden + + // Both links are displayed + if leftLinkIsDisplayed && rightLinkIsDisplayed { + isAccessibilityElement = false + var views = [UIView]() + + if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty { + views.append(eyebrow) + } + + if let headlineText = headline.text, !headlineText.isEmpty { + views.append(headline) + } + + if let bodyText = body.text, !bodyText.isEmpty { + views.append(body) + } + + if let body2Text = body2.text, !body2Text.isEmpty { + views.append(body2) + } + + views.append(twoLinkView.leftLink) + views.append(twoLinkView.rightLink) + + accessibilityElements = views + return + + } else if leftLinkIsDisplayed { + accessibilityHint = twoLinkView.leftLink.accessibilityHint + accessibilityTraits = twoLinkView.leftLink.accessibilityTraits + message += twoLinkView.leftLink.accessibilityLabel ?? "" + + } else if rightLinkIsDisplayed { + accessibilityHint = twoLinkView.rightLink.accessibilityHint + accessibilityTraits = twoLinkView.rightLink.accessibilityTraits + message += twoLinkView.rightLink.accessibilityLabel ?? "" + + } + + isAccessibilityElement = true + accessibilityLabel = message + } + + open override func accessibilityActivate() -> Bool { + + if isAccessibilityElement { + if !twoLinkView.leftLink.isHidden { + return twoLinkView.leftLink.accessibilityActivate() + } else if !twoLinkView.rightLink.isHidden { + return twoLinkView.rightLink.accessibilityActivate() + } + } + + return false + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMediumModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMediumModel.swift index 0e33d2bf..ea8abc44 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMediumModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMediumModel.swift @@ -7,7 +7,13 @@ // import Foundation + + public class ListDeviceComplexLinkMediumModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "listDvcLnkM" public var eyebrow: LabelModel? public var headline: LabelModel? @@ -16,6 +22,10 @@ public class ListDeviceComplexLinkMediumModel: ListItemModel, MoleculeModelProto public var twoLinkView: TwoLinkViewModel public var image: ImageViewModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(eyebrow: LabelModel, headline: LabelModel, body: LabelModel, body2: LabelModel, twoLinkView: TwoLinkViewModel, image: ImageViewModel) { self.eyebrow = eyebrow self.headline = headline @@ -26,6 +36,10 @@ public class ListDeviceComplexLinkMediumModel: ListItemModel, MoleculeModelProto super.init() } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case eyebrow @@ -36,6 +50,10 @@ public class ListDeviceComplexLinkMediumModel: ListItemModel, MoleculeModelProto case image } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmall.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmall.swift index 49173067..0e2881ce 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmall.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmall.swift @@ -7,11 +7,13 @@ // import Foundation + + @objcMembers open class ListDeviceComplexLinkSmall: TableViewCell { - //----------------------------------------------------- // MARK: - Outlets //----------------------------------------------------- + public let eyebrow = Label.createLabelRegularMicro(true) public let headline = Label.createLabelBoldTitleMedium(true) public let body = Label.createLabelRegularBodySmall(true) @@ -24,12 +26,18 @@ import Foundation //------------------------------------------------------ // MARK: - Initializers //------------------------------------------------------ + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { rightImage.addSizeConstraintsForAspectRatio = true rightImage.imageView.contentMode = .scaleAspectFit - rightImage.heightAnchor.constraint(equalToConstant: 71.0).isActive = true - rightImage.widthAnchor.constraint(equalToConstant: 71.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: twoLinkView, model: StackItemModel(spacing: 16, horizontalAlignment: .leading))], axis: .vertical, spacing: 0) + rightImage.heightAnchor.constraint(equalToConstant: 71).isActive = true + rightImage.widthAnchor.constraint(equalToConstant: 71).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: twoLinkView, model: StackItemModel(spacing: 16, horizontalAlignment: .leading))], + axis: .vertical, spacing: 0) stack = Stack.createStack(with: [(view: verticalStack, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .leading)), (view: rightImage, model: StackItemModel(verticalAlignment: .center))], @@ -42,24 +50,29 @@ import Foundation } //----------------------------------------------------- - // MARK: - View Lifecycle + // MARK: - Lifecycle //----------------------------------------------------- + open override func setupView() { super.setupView() rightImage.shouldNotifyDelegateOnUpdate = false addMolecule(stack) stack.restack() verticalStack.restack() + updateAccessibilityLabel() } //------------------------------------------------------ // MARK: - Molecule //------------------------------------------------------ - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListDeviceComplexLinkSmallModel else { return } + verticalStack.updateContainedMolecules(with: [model.eyebrow, model.headline, model.body, model.body2, model.twoLinkView], delegateObject, additionalData) rightImage.set(with: model.image, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -74,4 +87,91 @@ import Foundation body2.styleRegularBodySmall(true) eyebrow.textColor = .mvmCoolGray6 } + + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty { + message += eyebrowText + ", " + } + + if let headlineText = headline.text, !headlineText.isEmpty { + message += headlineText + ", " + } + + if let bodyText = body.text, !bodyText.isEmpty { + message += bodyText + ", " + } + + if let body2Text = body2.text, !body2Text.isEmpty { + message += body2Text + ", " + } + + if let rightImageLabel = rightImage.accessibilityLabel { + message += rightImageLabel + } + + let leftLinkIsDisplayed = !twoLinkView.leftLink.isHidden + let rightLinkIsDisplayed = !twoLinkView.rightLink.isHidden + + // Both links are displayed + if leftLinkIsDisplayed && rightLinkIsDisplayed { + isAccessibilityElement = false + var views = [UIView]() + + if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty { + views.append(eyebrow) + } + + if let headlineText = headline.text, !headlineText.isEmpty { + views.append(headline) + } + + if let bodyText = body.text, !bodyText.isEmpty { + views.append(body) + } + + if let body2Text = body2.text, !body2Text.isEmpty { + views.append(body2) + } + + views.append(twoLinkView.leftLink) + views.append(twoLinkView.rightLink) + + accessibilityElements = views + return + + } else if leftLinkIsDisplayed { + accessibilityHint = twoLinkView.leftLink.accessibilityHint + accessibilityTraits = twoLinkView.leftLink.accessibilityTraits + message += twoLinkView.leftLink.accessibilityLabel ?? "" + + } else if rightLinkIsDisplayed { + accessibilityHint = twoLinkView.rightLink.accessibilityHint + accessibilityTraits = twoLinkView.rightLink.accessibilityTraits + message += twoLinkView.rightLink.accessibilityLabel ?? "" + + } + + isAccessibilityElement = true + accessibilityLabel = message + } + + open override func accessibilityActivate() -> Bool { + + if isAccessibilityElement { + if !twoLinkView.leftLink.isHidden { + return twoLinkView.leftLink.accessibilityActivate() + } else if !twoLinkView.rightLink.isHidden { + return twoLinkView.rightLink.accessibilityActivate() + } + } + + return false + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmallModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmallModel.swift index f8784320..3bb9080f 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmallModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmallModel.swift @@ -7,7 +7,13 @@ // import Foundation + + public class ListDeviceComplexLinkSmallModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "listDvcLnkS" public var eyebrow: LabelModel? public var headline: LabelModel? @@ -16,6 +22,10 @@ public class ListDeviceComplexLinkSmallModel: ListItemModel, MoleculeModelProtoc public var twoLinkView: TwoLinkViewModel public var image: ImageViewModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(eyebrow: LabelModel, headline: LabelModel, body: LabelModel, body2: LabelModel, twoLinkView: TwoLinkViewModel, image: ImageViewModel) { self.eyebrow = eyebrow self.headline = headline @@ -26,6 +36,10 @@ public class ListDeviceComplexLinkSmallModel: ListItemModel, MoleculeModelProtoc super.init() } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case eyebrow @@ -36,6 +50,10 @@ public class ListDeviceComplexLinkSmallModel: ListItemModel, MoleculeModelProtoc case image } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItem.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItem.swift index a42b6797..9520052e 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItem.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItem.swift @@ -8,32 +8,34 @@ import Foundation + @objcMembers public class ListFourColumnDataUsageListItem: TableViewCell { - //----------------------------------------------------- // MARK: - Outlets //----------------------------------------------------- + var stack: Stack let label1 = Label.createLabelRegularBodySmall(true) let label2 = Label.createLabelRegularBodySmall(true) let label3 = Label.createLabelRegularBodySmall(true) let label4 = Label.createLabelRegularBodySmall(true) - let arrow = Arrow(frame: .zero) + let arrow = Arrow() let arrowAndLabel2Stack: Stack //----------------------------------------------------- // MARK: - Initializers //----------------------------------------------------- + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { arrowAndLabel2Stack = Stack.createStack(with: [(view: arrow, model: StackItemModel(horizontalAlignment: .fill)), - (view: label2, model: StackItemModel(horizontalAlignment: .leading))], + (view: label2, model: StackItemModel(horizontalAlignment: .leading))], axis: .horizontal, spacing: 4) label2.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) label2.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal) stack = Stack.createStack(with: [(view: label1, model: StackItemModel(percent: 19, horizontalAlignment: .leading)), (view: arrowAndLabel2Stack, model: StackItemModel(percent: 44, horizontalAlignment: .fill)), - (view: label3, model: StackItemModel(percent:17,horizontalAlignment: .leading)), - (view: label4, model: StackItemModel(percent:20,horizontalAlignment: .leading))], + (view: label3, model: StackItemModel(percent:17, horizontalAlignment: .leading)), + (view: label4, model: StackItemModel(percent:20, horizontalAlignment: .leading))], axis: .horizontal,spacing: 8) super.init(style: style, reuseIdentifier: reuseIdentifier) } @@ -43,24 +45,34 @@ import Foundation } //----------------------------------------------------- - // MARK: - View Lifecycle + // MARK: - Lifecycle //----------------------------------------------------- + override open func setupView() { super.setupView() addMolecule(stack) arrow.pinHeightAndWidth() arrowAndLabel2Stack.restack() stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + //----------------------------------------------------- + // MARK: - Molecular + //----------------------------------------------------- + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListFourColumnDataUsageListItemModel else { return } + label1.set(with: model.label1, delegateObject, additionalData) label2.set(with: model.label2, delegateObject, additionalData) label3.set(with: model.label3, delegateObject, additionalData) label4.set(with: model.label4, delegateObject, additionalData) arrow.set(with: model.arrow, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -74,4 +86,31 @@ import Foundation label3.styleRegularBodySmall(true) label4.styleRegularBodySmall(true) } + + //----------------------------------------------------- + // MARK: - Accessibility + //----------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let label1Text = label1.text, !label1Text.isEmpty { + message += label1Text + ", " + } + + if let label2Text = label2.text, !label2Text.isEmpty { + message += label2Text + ", " + } + + if let label3Text = label3.text, !label3Text.isEmpty { + message += label3Text + ", " + } + + if let label4Text = label4.text, !label4Text.isEmpty { + message += label4Text + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItemModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItemModel.swift index bf82bb5f..dbd66ccd 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItemModel.swift @@ -8,7 +8,12 @@ import Foundation + public class ListFourColumnDataUsageListItemModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "list4C" public var label1: LabelModel public var arrow: ArrowModel @@ -16,6 +21,10 @@ public class ListFourColumnDataUsageListItemModel: ListItemModel, MoleculeModelP public var label3: LabelModel public var label4: LabelModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(label1:LabelModel, label2:LabelModel, label3:LabelModel,label4:LabelModel, arrow:ArrowModel) { self.label1 = label1 self.label2 = label2 @@ -25,6 +34,10 @@ public class ListFourColumnDataUsageListItemModel: ListItemModel, MoleculeModelP super.init() } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case label1 @@ -34,6 +47,10 @@ public class ListFourColumnDataUsageListItemModel: ListItemModel, MoleculeModelP case arrow } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) label1 = try typeContainer.decode(LabelModel.self, forKey: .label1) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyText.swift index 1f982f4f..7bd37790 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyText.swift @@ -22,6 +22,7 @@ import Foundation //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { stack = Stack.createStack(with: [(view: leftImage, model: StackItemModel(horizontalAlignment: .fill)), (view: headlineBody, model: StackItemModel(horizontalAlignment: .leading)), @@ -75,6 +76,10 @@ import Foundation rightLabel.styleRegularBodySmall(true) } + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + func updateAccessibilityLabel() { var message = "" diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableNumberedListAllTextAndLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableNumberedListAllTextAndLinks.swift index 93daa015..1a01b113 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableNumberedListAllTextAndLinks.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableNumberedListAllTextAndLinks.swift @@ -78,6 +78,10 @@ import Foundation eyebrowHeadlineBodyLink.body.preferredMaxLayoutWidth = eyebrowHeadlineBodyLink.frame.width } + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + func updateAccessibilityLabel() { var message = "" diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAllTextAndLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAllTextAndLinks.swift index fc26e38b..5756d4f5 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAllTextAndLinks.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAllTextAndLinks.swift @@ -46,7 +46,7 @@ import Foundation accessibilityTraits = radioButton.accessibilityTraits accessibilityHint = radioButton.accessibilityHint - + updateAccessibilityLabel() // Update accessibility label on radio button state change. observation = observe(\.radioButton.isSelected, options: [.new]) { [weak self] _, _ in self?.updateAccessibilityLabel() @@ -59,7 +59,9 @@ import Foundation open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) - guard let model = model as? ListLeftVariableRadioButtonAllTextAndLinksModel else { return} + + guard let model = model as? ListLeftVariableRadioButtonAllTextAndLinksModel else { return } + radioButton.set(with: model.radioButton, delegateObject, additionalData) eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData) updateAccessibilityLabel() @@ -73,6 +75,10 @@ import Foundation radioButton.tapAction() } + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + func updateAccessibilityLabel() { var message = "" diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index 4eaa3fd4..451c60c7 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -89,6 +89,10 @@ import UIKit radioButton.tapAction() } + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + func updateAccessibilityLabel() { var message = "" diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index 189c08d0..860b78f8 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -80,6 +80,10 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { radioButton.tapAction() } + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + func updateAccessibilityLabel() { var message = "" diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift index e1e9d758..f3e2b74a 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift @@ -68,6 +68,10 @@ import Foundation body.styleRegularBodySmall(true) } + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + func updateAccessibilityLabel() { var message = "" diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeAllTextAndLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeAllTextAndLinks.swift index 1c1c941f..5f715f5f 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeAllTextAndLinks.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeAllTextAndLinks.swift @@ -64,9 +64,7 @@ import Foundation rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal) rightLabel.numberOfLines = 1 - arrow.pinHeightAndWidth() - addMolecule(stack) stack.restack() updateAccessibilityLabel() diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnDataUsage.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnDataUsage.swift index 5e7d39c6..fc16bd4b 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnDataUsage.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnDataUsage.swift @@ -8,11 +8,12 @@ import Foundation + @objcMembers open class ListThreeColumnDataUsage: TableViewCell { - //----------------------------------------------------- // MARK: - Outlets - //------------------------------------------------------- + //----------------------------------------------------- + public let leftLabel = Label.createLabelRegularBodySmall(true) public let centerLabel = Label.createLabelRegularBodySmall(true) public let rightLabel = Label.createLabelRegularBodySmall(true) @@ -21,6 +22,7 @@ import Foundation //------------------------------------------------------ // MARK: - Initializers //------------------------------------------------------ + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 40, horizontalAlignment: .leading)), (view: centerLabel, model: StackItemModel(percent: 37, horizontalAlignment: .leading)), @@ -33,24 +35,36 @@ import Foundation fatalError("init(coder:) has not been implemented") } + //------------------------------------------------------ + // MARK: - Lifecycle + //------------------------------------------------------ + open override func setupView() { - super.setupView() - addMolecule(stack) - stack.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? ListThreeColumnDataUsageModel else { return } - leftLabel.set(with: model.leftLabel, delegateObject, additionalData) - centerLabel.set(with: model.centerLabel, delegateObject, additionalData) - rightLabel.set(with: model.rightLabel, delegateObject, additionalData) - } - - open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return 121 - } + super.setupView() + addMolecule(stack) + stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() + } + + //-------------------------------------------------- + // 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? ListThreeColumnDataUsageModel else { return } + + leftLabel.set(with: model.leftLabel, delegateObject, additionalData) + centerLabel.set(with: model.centerLabel, delegateObject, additionalData) + rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + updateAccessibilityLabel() + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 121 + } open override func reset() { super.reset() @@ -58,4 +72,27 @@ import Foundation centerLabel.styleRegularBodySmall(true) rightLabel.styleRegularBodySmall(true) } + + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let leftText = leftLabel.text, !leftText.isEmpty { + message += leftText + ", " + } + + if let centerText = centerLabel.text, !centerText.isEmpty { + message += centerText + ", " + } + + if let rightText = rightLabel.text, !rightText.isEmpty { + message += rightText + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnDataUsageModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnDataUsageModel.swift index 56f1e402..7f49779a 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnDataUsageModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnDataUsageModel.swift @@ -8,12 +8,21 @@ import Foundation + public class ListThreeColumnDataUsageModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "list3CDataUsg" public var leftLabel: LabelModel public var centerLabel: LabelModel public var rightLabel: LabelModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(leftLabel:LabelModel, centerLabel:LabelModel, rightLabel:LabelModel) { self.leftLabel = leftLabel self.centerLabel = centerLabel @@ -21,6 +30,10 @@ public class ListThreeColumnDataUsageModel: ListItemModel, MoleculeModelProtocol super.init() } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case leftLabel @@ -28,6 +41,10 @@ public class ListThreeColumnDataUsageModel: ListItemModel, MoleculeModelProtocol case rightLabel } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) @@ -45,4 +62,3 @@ public class ListThreeColumnDataUsageModel: ListItemModel, MoleculeModelProtocol try container.encode(rightLabel, forKey: .rightLabel) } } - diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnInternationalData.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnInternationalData.swift index 5fc836d1..359bae7d 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnInternationalData.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnInternationalData.swift @@ -8,24 +8,28 @@ import Foundation + @objcMembers public class ListThreeColumnInternationalData: TableViewCell { //----------------------------------------------------- // MARK: - Outlets //----------------------------------------------------- + open var stack: Stack public let leftLabel = Label.createLabelRegularBodySmall(true) public let centerLabel = Label.createLabelRegularBodySmall(true) public let rightLabel = Label.createLabelRegularBodySmall(true) - public let arrow = Arrow(frame: .zero) + public let arrow = Arrow() public let arrowAndLabel2Stack: Stack - + //----------------------------------------------------- // MARK: - Initializers //----------------------------------------------------- + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + arrowAndLabel2Stack = Stack.createStack(with: [(view: arrow, model: StackItemModel(horizontalAlignment: .fill)), - (view: centerLabel, model: StackItemModel(horizontalAlignment: .leading))], + (view: centerLabel, model: StackItemModel(horizontalAlignment: .leading))], axis: .horizontal, spacing: 4) centerLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) centerLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal) @@ -41,23 +45,30 @@ import Foundation } //----------------------------------------------------- - // MARK: - View Lifecycle + // MARK: - Lifecycle //----------------------------------------------------- + override open func setupView() { super.setupView() + addMolecule(stack) arrow.pinHeightAndWidth() arrowAndLabel2Stack.restack() stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListThreeColumnInternationalDataModel else { return } + leftLabel.set(with: model.leftLabel, delegateObject, additionalData) centerLabel.set(with: model.centerLabel, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData) arrow.set(with: model.arrow, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -70,4 +81,27 @@ import Foundation centerLabel.styleRegularBodySmall(true) rightLabel.styleRegularBodySmall(true) } + + //-------------------------------------------------- + // MARK: - Accessibility + //-------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let leftText = leftLabel.text, !leftText.isEmpty { + message += leftText + ", " + } + + if let centerText = centerLabel.text, !centerText.isEmpty { + message += centerText + ", " + } + + if let rightText = rightLabel.text, !rightText.isEmpty { + message += rightText + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnInternationalDataModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnInternationalDataModel.swift index d0cd3791..01a2d3f5 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnInternationalDataModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ThreeColumn/ListThreeColumnInternationalDataModel.swift @@ -8,13 +8,22 @@ import Foundation + public class ListThreeColumnInternationalDataModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "list3CIntData" public var leftLabel: LabelModel public var centerLabel: LabelModel public var rightLabel: LabelModel public var arrow: ArrowModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(leftLabel:LabelModel, centerLabel:LabelModel, rightLabel:LabelModel, arrow:ArrowModel) { self.leftLabel = leftLabel self.centerLabel = centerLabel @@ -23,6 +32,10 @@ public class ListThreeColumnInternationalDataModel: ListItemModel, MoleculeModel super.init() } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case leftLabel @@ -31,6 +44,10 @@ public class ListThreeColumnInternationalDataModel: ListItemModel, MoleculeModel case arrow } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/FourColumn/ListFourColumnDataUsageDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/FourColumn/ListFourColumnDataUsageDivider.swift index c205f8b5..d8ab112c 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/FourColumn/ListFourColumnDataUsageDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/FourColumn/ListFourColumnDataUsageDivider.swift @@ -45,6 +45,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //-------------------------------------------------- @@ -60,6 +62,7 @@ import Foundation label2.set(with: model.label2, delegateObject, additionalData) label3.set(with: model.label3, delegateObject, additionalData) label4.set(with: model.label4, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -73,4 +76,29 @@ import Foundation label3.styleBoldBodySmall(true) label4.styleBoldBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let label1Text = label1.text, !label1Text.isEmpty { + message += label1Text + ", " + } + + if let label2Text = label2.text, !label2Text.isEmpty { + message += label2Text + ", " + } + if let label3Text = label3.text, !label3Text.isEmpty { + message += label3Text + ", " + } + if let label4Text = label4.text, !label4Text.isEmpty { + message += label4Text + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift index cf78e88a..88ad013f 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift @@ -41,6 +41,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //-------------------------------------------------- @@ -54,6 +56,7 @@ import Foundation headline.set(with: model.headline, delegateObject, additionalData) body.set(with: model.body, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -65,4 +68,23 @@ import Foundation headline.styleBoldBodySmall(true) body.styleRegularBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let headlineLabel = headline.text, !headlineLabel.isEmpty { + message += headlineLabel + ", " + } + + if let bodyLabel = body.text, !bodyLabel.isEmpty { + message += bodyLabel + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift index cb24166e..204f85a2 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift @@ -41,6 +41,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //-------------------------------------------------- @@ -54,6 +56,7 @@ import Foundation headline.set(with: model.headline, delegateObject, additionalData) body.set(with: model.body, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -65,4 +68,23 @@ import Foundation headline.styleBoldTitleMedium(true) body.styleRegularBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let headlineLabel = headline.text, !headlineLabel.isEmpty { + message += headlineLabel + ", " + } + + if let bodyLabel = body.text, !bodyLabel.isEmpty { + message += bodyLabel + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift index 369b1830..44462f86 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift @@ -40,6 +40,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //-------------------------------------------------- @@ -53,6 +55,7 @@ import Foundation headline.set(with: model.headline, delegateObject, additionalData) body.set(with: model.body, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -64,4 +67,23 @@ import Foundation headline.styleBoldTitleMedium(true) body.styleRegularBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let headlineLabel = headline.text, !headlineLabel.isEmpty { + message += headlineLabel + ", " + } + + if let bodyLabel = body.text, !bodyLabel.isEmpty { + message += bodyLabel + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnBillChangesDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnBillChangesDivider.swift index 0ce38c3f..1ef40129 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnBillChangesDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnBillChangesDivider.swift @@ -43,6 +43,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //----------------------------------------------------- @@ -57,6 +59,7 @@ import Foundation leftLabel.set(with: model.leftLabel, delegateObject, additionalData) centerLabel.set(with: model.centerLabel, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -69,4 +72,27 @@ import Foundation centerLabel.styleBoldBodySmall(true) rightLabel.styleBoldBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let leftLabeltext = leftLabel.text, !leftLabeltext.isEmpty { + message += leftLabeltext + ", " + } + + if let centerLabeltext = centerLabel.text, !centerLabeltext.isEmpty { + message += centerLabeltext + ", " + } + + if let rightLabeltext = rightLabel.text, !rightLabeltext.isEmpty { + message += rightLabeltext + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift index 273db822..6f7881fd 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift @@ -43,6 +43,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //----------------------------------------------------- @@ -57,6 +59,7 @@ import Foundation leftLabel.set(with: model.leftLabel, delegateObject, additionalData) centerLabel.set(with: model.centerLabel, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -69,4 +72,27 @@ import Foundation centerLabel.styleBoldBodySmall(true) rightLabel.styleBoldBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let leftLabeltext = leftLabel.text, !leftLabeltext.isEmpty { + message += leftLabeltext + ", " + } + + if let centerLabeltext = centerLabel.text, !centerLabeltext.isEmpty { + message += centerLabeltext + ", " + } + + if let rightLabeltext = rightLabel.text, !rightLabeltext.isEmpty { + message += rightLabeltext + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnInternationalDataDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnInternationalDataDivider.swift index 9623c1d2..06f447a8 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnInternationalDataDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnInternationalDataDivider.swift @@ -43,6 +43,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //----------------------------------------------------- @@ -56,6 +58,7 @@ import Foundation leftLabel.set(with: model.leftLabel, delegateObject, additionalData) centerLabel.set(with: model.centerLabel, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -68,4 +71,27 @@ import Foundation centerLabel.styleBoldBodySmall(true) rightLabel.styleBoldBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let leftLabeltext = leftLabel.text, !leftLabeltext.isEmpty { + message += leftLabeltext + ", " + } + + if let centerLabeltext = centerLabel.text, !centerLabeltext.isEmpty { + message += centerLabeltext + ", " + } + + if let rightLabeltext = rightLabel.text, !rightLabeltext.isEmpty { + message += rightLabeltext + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift index 760c46c2..9e5c2f05 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift @@ -43,6 +43,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //----------------------------------------------------- @@ -57,9 +59,45 @@ import Foundation leftHeadlineBody.set(with: model.leftHeadlineBody, delegateObject, additionalData) centerHeadLineBody.set(with: model.centerHeadlineBody, delegateObject, additionalData) rightHeadLineBody.set(with: model.rightHeadlineBody, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 121 } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let headlineLabel = leftHeadlineBody.headlineLabel.text { + message += headlineLabel + ", " + } + + if let messageLabel = leftHeadlineBody.messageLabel.text { + message += messageLabel + ", " + } + + if let headlineLabel = centerHeadLineBody.headlineLabel.text { + message += headlineLabel + ", " + } + + if let messageLabel = centerHeadLineBody.messageLabel.text { + message += messageLabel + ", " + } + + if let headlineLabel = rightHeadLineBody.headlineLabel.text { + message += headlineLabel + ", " + } + + if let messageLabel = rightHeadLineBody.messageLabel.text { + message += messageLabel + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift index b374ef1b..d2355878 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift @@ -24,7 +24,10 @@ import Foundation //------------------------------------------------------- public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 37, horizontalAlignment: .leading)), (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .leading)), (view: rightLabel, model: StackItemModel(percent: 30, horizontalAlignment: .leading))], axis: .horizontal) + stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 37, horizontalAlignment: .leading)), + (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .leading)), + (view: rightLabel, model: StackItemModel(percent: 30, horizontalAlignment: .leading))], + axis: .horizontal) super.init(style: style, reuseIdentifier: reuseIdentifier) } @@ -40,6 +43,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //------------------------------------------------------ @@ -48,10 +53,13 @@ import Foundation open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListThreeColumnSpeedTestDividerModel else { return } + leftLabel.set(with: model.leftLabel, delegateObject, additionalData) centerLabel.set(with: model.centerLabel, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -64,4 +72,27 @@ import Foundation centerLabel.styleBoldBodySmall(true) rightLabel.styleBoldBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let leftLabeltext = leftLabel.text, !leftLabeltext.isEmpty { + message += leftLabeltext + ", " + } + + if let centerLabeltext = centerLabel.text, !centerLabeltext.isEmpty { + message += centerLabeltext + ", " + } + + if let rightLabeltext = rightLabel.text, !rightLabeltext.isEmpty { + message += rightLabeltext + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/TwoColumn/ListTwoColumnSubsectionDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/TwoColumn/ListTwoColumnSubsectionDivider.swift index f23cade1..4a3abce1 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/TwoColumn/ListTwoColumnSubsectionDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/TwoColumn/ListTwoColumnSubsectionDivider.swift @@ -41,6 +41,8 @@ import Foundation super.setupView() addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() } //-------------------------------------------------- @@ -54,6 +56,7 @@ import Foundation leftLabel.set(with: model.leftLabel, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { @@ -65,4 +68,23 @@ import Foundation leftLabel.styleBoldBodySmall(true) rightLabel.styleBoldBodySmall(true) } + + //---------------------------------------------------- + // MARK: - Accessibility + //---------------------------------------------------- + + func updateAccessibilityLabel() { + + var message = "" + + if let leftLabeltext = leftLabel.text, !leftLabeltext.isEmpty { + message += leftLabeltext + ", " + } + + if let rightLabeltext = rightLabel.text, !rightLabeltext.isEmpty { + message += rightLabeltext + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoLinkView.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoLinkView.swift index ed2ff2fb..fbc56b0b 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoLinkView.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoLinkView.swift @@ -8,11 +8,20 @@ import Foundation + @objcMembers open class TwoLinkView: View, MVMCoreUIViewConstrainingProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + open var leftLink = Link() open var rightLink = Link() private var stack = UIStackView() + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + public init() { super.init(frame: .zero) } @@ -25,7 +34,10 @@ import Foundation super.init(frame: frame) } + //-------------------------------------------------- // MARK: - MVMCoreViewProtocol + //-------------------------------------------------- + open override func updateView(_ size: CGFloat) { super.updateView(size) stack.updateView(size) @@ -43,7 +55,10 @@ import Foundation stack.spacing = 8 } + //-------------------------------------------------- // MARK: - Stack Manipulation + //-------------------------------------------------- + public func showRightLink() { if !stack.arrangedSubviews.contains(rightLink) { stack.addArrangedSubview(rightLink) @@ -72,18 +87,27 @@ import Foundation } } + //-------------------------------------------------- // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + open override func reset() { super.reset() stack.reset() } + //-------------------------------------------------- // MARK: - MVMCoreUIViewConstrainingProtocol + //-------------------------------------------------- + open func horizontalAlignment() -> UIStackView.Alignment { return .center } + //-------------------------------------------------- // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return 16 } @@ -99,6 +123,7 @@ import Foundation } else { hideLeftLink() } + if let model = model.rightLink { showRightLink() rightLink.set(with: model, delegateObject, additionalData)