From b2fee17d8ae228d262fd8831661b52e760b06012 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 17 Apr 2020 16:58:07 -0400 Subject: [PATCH 01/10] changes made to resolve VO issues --- .../Templates/ModalMoleculeListTemplate.swift | 3 +++ .../ThreeLayerTableViewController.swift | 1 + .../Views/Container/ContainerHelper.swift | 20 +++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift index eda35d6b..eb85d80b 100644 --- a/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift @@ -17,5 +17,8 @@ open class ModalMoleculeListTemplate: MoleculeListTemplate { closeButton = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: { _ in MVMCoreNavigationHandler.shared()?.removeCurrentViewController() }, verticalCentered: false) + + accessibilityElements = [closeButton as Any, tableView as Any] + UIAccessibility.post(notification: .layoutChanged, argument: closeButton) } } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 000f2e7f..bc5778b7 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -41,6 +41,7 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController { createViewForTableHeader() createViewForTableFooter() tableView?.reloadData() + accessibilityElements = [tableView as Any] } override open func viewDidLoad() { diff --git a/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift b/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift index 223589fe..fcb8877e 100644 --- a/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift +++ b/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift @@ -9,7 +9,12 @@ import Foundation + open class ContainerHelper: NSObject { + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + var leftConstraint: NSLayoutConstraint? var topConstraint: NSLayoutConstraint? var bottomConstraint: NSLayoutConstraint? @@ -28,17 +33,26 @@ open class ContainerHelper: NSObject { var bottomLowConstraint: NSLayoutConstraint? var rightLowConstraint: NSLayoutConstraint? + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + open func constrainView(_ view: UIView) { guard let margins = view.superview?.layoutMarginsGuide else { return } + + leftConstraint?.isActive = false leftConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor) leftConstraint?.isActive = true + topConstraint?.isActive = false topConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor) topConstraint?.isActive = true + rightConstraint?.isActive = false rightConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor) rightConstraint?.isActive = true + bottomConstraint?.isActive = false bottomConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor) bottomConstraint?.isActive = true @@ -50,23 +64,25 @@ open class ContainerHelper: NSObject { alignCenterTopConstraint = view.topAnchor.constraint(greaterThanOrEqualTo: margins.topAnchor) alignCenterBottomConstraint = margins.bottomAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor) + leftLowConstraint?.isActive = false leftLowConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor) leftLowConstraint?.priority = UILayoutPriority(rawValue: 200) leftLowConstraint?.isActive = true + topLowConstraint?.isActive = false topLowConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor) topLowConstraint?.priority = UILayoutPriority(rawValue: 200) topLowConstraint?.isActive = true + rightLowConstraint?.isActive = false rightLowConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor) rightLowConstraint?.priority = UILayoutPriority(rawValue: 200) rightLowConstraint?.isActive = true + bottomLowConstraint?.isActive = false bottomLowConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor) bottomLowConstraint?.priority = UILayoutPriority(rawValue: 200) bottomLowConstraint?.isActive = true - - setAccessibility(view) } open func setAccessibility(_ view: UIView) { From ac158381beff308121db01ac38d3085054ed489b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 27 Apr 2020 15:06:09 -0400 Subject: [PATCH 02/10] accessibility as a cell --- ...tVariableRadioButtonAndPaymentMethod.swift | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index 7bf1ff6a..d32f048f 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -46,6 +46,11 @@ import UIKit stack.restack() eyebrowHeadlineBodyLink.body.textColor = .mvmOrangeAA eyebrowHeadlineBodyLink.headline.styleBoldBodySmall(true) + + isAccessibilityElement = true + updateAccessibilityLabel() + accessibilityTraits = .button + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") } open override func reset() { @@ -64,6 +69,7 @@ import UIKit radioButton.set(with: model.radioButton, delegateObject, additionalData) leftImage.set(with: model.image, delegateObject, additionalData) eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -73,4 +79,31 @@ import UIKit public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { radioButton.tapAction() } + + func updateAccessibilityLabel() { + + var message = "Radio Button, " + + if let radioButtonLabel = radioButton.accessibilityLabel { + message += radioButtonLabel + ", " + } + + if let leftImageLabel = leftImage.accessibilityLabel { + message += leftImageLabel + ", " + } + + if let eyebrowLabel = eyebrowHeadlineBodyLink.eyebrow.text { + message += eyebrowLabel + ", " + } + + if let headlineLabel = eyebrowHeadlineBodyLink.headline.text { + message += headlineLabel + ", " + } + + if let bodyLabel = eyebrowHeadlineBodyLink.eyebrow.text { + message += bodyLabel + } + + accessibilityLabel = message + } } From 8e47e4ceb3c522e89960b061f7ea6a47536db189 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 08:33:23 -0400 Subject: [PATCH 03/10] customized accessibility for cell --- MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift | 2 +- .../ListLeftVariableRadioButtonAndPaymentMethod.swift | 8 ++++---- MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m | 10 ++++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift index 2b22fcee..aa73e7b5 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift @@ -127,7 +127,7 @@ import UIKit func updateAccessibilityLabel() { if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "radio_selected_state" : "radio_not_selected_state") { - accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "radio_desc_state") ?? "%@%@", "", state) + accessibilityLabel = state } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index d32f048f..1c1ddada 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -77,13 +77,13 @@ import UIKit } public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - radioButton.tapAction() + radioButton.tapAction() } func updateAccessibilityLabel() { var message = "Radio Button, " - + if let radioButtonLabel = radioButton.accessibilityLabel { message += radioButtonLabel + ", " } @@ -100,10 +100,10 @@ import UIKit message += headlineLabel + ", " } - if let bodyLabel = eyebrowHeadlineBodyLink.eyebrow.text { + if let bodyLabel = eyebrowHeadlineBodyLink.body.text { message += bodyLabel } - + accessibilityLabel = message } } diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m index 6fc7121f..b2c4785a 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m @@ -301,11 +301,13 @@ [weakSelf.viewToLayout layoutIfNeeded]; }; + //accessibility - added to make only top alert label and close button accessible. Posted notification when top alert is displayed + weakSelf.accessibilityElements = @[weakSelf.buttonView]; + weakSelf.shortView.isAccessibilityElement = NO; + weakSelf.buttonView.label.accessibilityLabel = [NSString stringWithFormat:@"%@ - %@", [MVMCoreUIUtility hardcodedStringWithKey:@"top_alert_notification"],weakSelf.buttonView.label.accessibilityLabel]; + void(^completion)(void) = ^(void) { - //accessibility - added to make only top alert label and close button accessible. Posted notification when top alert is displayed - weakSelf.accessibilityElements = @[weakSelf.buttonView]; - weakSelf.shortView.isAccessibilityElement = NO; - weakSelf.buttonView.label.accessibilityLabel = [NSString stringWithFormat:@"%@ - %@", [MVMCoreUIUtility hardcodedStringWithKey:@"top_alert_notification"],weakSelf.buttonView.label.accessibilityLabel]; + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, weakSelf.buttonView.label); [operation markAsFinished]; }; From b92358cca992b7606c85c48f2322e6182fddbb76 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 09:38:28 -0400 Subject: [PATCH 04/10] further accessibility updates. --- ...tVariableRadioButtonAndPaymentMethod.swift | 3 ++- .../ListLeftVariableRadioButtonBodyText.swift | 27 ++++++++++++++++++- .../Items/MoleculeListItemModel.swift | 19 ++++++++++++- .../Items/MoleculeTableViewCell.swift | 3 ++- .../Templates/ModalMoleculeListTemplate.swift | 9 ++++++- .../Templates/MoleculeListTemplate.swift | 6 ++++- .../Strings/en.lproj/Localizable.strings | 1 + 7 files changed, 62 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index 1c1ddada..5ad9110a 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -82,8 +82,9 @@ import UIKit func updateAccessibilityLabel() { - var message = "Radio Button, " + var message = MVMCoreUIUtility.hardcodedString(withKey: "radio_button") ?? "" + radioButton.updateAccessibilityLabel() if let radioButtonLabel = radioButton.accessibilityLabel { message += radioButtonLabel + ", " } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index 9b45eec7..b87c9b6c 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -14,7 +14,7 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { // MARK: - Outlets //----------------------------------------------------- - let radioButton = RadioButton(frame: .zero) + let radioButton = RadioButton() let headlineBody = HeadlineBody() var stack: Stack @@ -42,6 +42,10 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() + accessibilityTraits = .button + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") } //---------------------------------------------------- @@ -55,6 +59,7 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { radioButton.set(with: model.radioButton, delegateObject, additionalData) headlineBody.set(with: model.headlineBody, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -64,4 +69,24 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { radioButton.tapAction() } + + func updateAccessibilityLabel() { + + var message = MVMCoreUIUtility.hardcodedString(withKey: "radio_button") ?? "" + + radioButton.updateAccessibilityLabel() + if let radioButtonLabel = radioButton.accessibilityLabel { + message += radioButtonLabel + ", " + } + + if let headlineLabel = headlineBody.headlineLabel.text { + message += headlineLabel + ", " + } + + if let messageLabel = headlineBody.messageLabel.text { + message += messageLabel + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeListItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeListItemModel.swift index 1384ee88..bee9d612 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeListItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeListItemModel.swift @@ -9,21 +9,39 @@ import Foundation import MVMCore + @objcMembers public class MoleculeListItemModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public class var identifier: String { return "listItem" } + public var molecule: MoleculeModelProtocol + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case molecule } + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(with moleculeModel: MoleculeModelProtocol) { molecule = moleculeModel super.init() } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) @@ -38,4 +56,3 @@ import MVMCore try container.encodeModel(molecule, forKey: .molecule) } } - diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeTableViewCell.swift index 0c9dec3b..6e1f2965 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeTableViewCell.swift @@ -10,8 +10,9 @@ import UIKit @objcMembers open class MoleculeTableViewCell: TableViewCell { - + //-------------------------------------------------- // MARK: - MoleculeViewProtocol + //-------------------------------------------------- public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { diff --git a/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift index eb85d80b..c9ba09b7 100644 --- a/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift @@ -9,9 +9,16 @@ import UIKit open class ModalMoleculeListTemplate: MoleculeListTemplate { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- public var closeButton: MFCustomButton? - + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + override open func handleNewData() { super.handleNewData() closeButton = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: { _ in diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index e40fbc33..521a0d45 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -12,6 +12,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //-------------------------------------------------- // MARK: - Stored Properties //-------------------------------------------------- + public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]? var observer: NSKeyValueObservation? @@ -208,8 +209,11 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol func getMoleculeInfo(with listItem: (ListItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: ListItemModelProtocol & MoleculeModelProtocol)? { guard let listItem = listItem, - let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(listItem) else { return nil } + let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(listItem) + else { return nil } + let moleculeName = moleculeClass.nameForReuse(with: listItem, delegateObject() as? MVMCoreUIDelegateObject) ?? listItem.moleculeName + return (moleculeName, moleculeClass, listItem) } diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 48cbe3ce..62c5be46 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -53,6 +53,7 @@ // MARK: Radio Button +"radio_button" = "Radio Button,"; "radio_action_hint" = "Double tap to select"; "radio_selected_state" = "Selected"; "radio_not_selected_state" = "Not Selected"; From 016eb01908ec7b632fd6581aea1f3036c9919d28 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 11:09:19 -0400 Subject: [PATCH 05/10] accessibility --- .../List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index b87c9b6c..f1ac9637 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -68,6 +68,7 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { radioButton.tapAction() + updateAccessibilityLabel() } func updateAccessibilityLabel() { From c6eb090bb799cd96763683ff1638184a380bbf90 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 12:10:42 -0400 Subject: [PATCH 06/10] accessibility --- .../Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift index c887e838..8630e607 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift @@ -10,7 +10,7 @@ import UIKit // This class is only temporarily necessary. Eventually we will have initWithModel instad of just init for moleculeviews, which will remove this need. open class StringAndMoleculeStack: MoleculeStackView { - override open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + override open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let model = model as? StackModelProtocol, let molcules = model.molecules as? [MoleculeStackItemModel] else { return } for stackItemModel in molcules { From 8be9c5aa8741453ed0da6bf4266fc2a0727f1204 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 12:42:17 -0400 Subject: [PATCH 07/10] accessibility --- .../RadioButtonSelectionHelper.swift | 27 ++++++++++--------- ...ableRadioButtonAndPaymentMethodModel.swift | 20 ++++++++++++++ 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift index 5196bb9c..4765766b 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift @@ -19,22 +19,22 @@ import Foundation private var selectedRadioButton: RadioButton? private var selectedRadioButtonModel: RadioButtonModel? public var baseValue: AnyHashable? - -//-------------------------------------------------- -// MARK: - Initializer -//-------------------------------------------------- - + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public func set(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton) { self.fieldKey = radioButtonModel.fieldKey self.groupName = radioButtonModel.groupName - + if radioButtonModel.state { if self.baseValue == nil, let selected = radioButtonModel.baseValue as? Bool, selected { self.baseValue = radioButtonModel.fieldValue } selectedRadioButtonModel = radioButtonModel - + // Below code is needed for cell resuse scenario. radioButton.isSelected = true selectedRadioButton = radioButton @@ -50,24 +50,24 @@ import Foundation public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton, delegateObject: MVMCoreUIDelegateObject?) { guard let groupName = radioButtonModel.fieldKey, - let formValidator = delegateObject?.formHolderDelegate?.formValidator else { - return - } - + let formValidator = delegateObject?.formHolderDelegate?.formValidator + else { return } + let radioButtonSelectionHelper = formValidator.radioButtonsModelByGroup[groupName] ?? RadioButtonSelectionHelper() radioButtonSelectionHelper.set(radioButtonModel, radioButton) formValidator.radioButtonsModelByGroup[groupName] = radioButtonSelectionHelper FormValidator.setupValidation(for: radioButtonSelectionHelper, delegate: delegateObject?.formHolderDelegate) } - + public func selected(_ radioButton: RadioButton) { + // Checks because the view could be reused if selectedRadioButton?.radioModel === selectedRadioButtonModel { selectedRadioButton?.isSelected = false } else { selectedRadioButtonModel?.state = false } - + selectedRadioButton = radioButton selectedRadioButton?.isSelected = true selectedRadioButtonModel = selectedRadioButton?.radioModel @@ -76,6 +76,7 @@ import Foundation // MARK: - FormValidationFormFieldProtocol extension RadioButtonSelectionHelper { + public func formFieldValue() -> AnyHashable? { return selectedRadioButtonModel?.fieldValue } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethodModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethodModel.swift index 5ea28778..f455882e 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethodModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethodModel.swift @@ -9,11 +9,19 @@ import Foundation public class ListLeftVariableRadioButtonAndPaymentMethodModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "listLVRBImg" public var radioButton: RadioButtonModel public var image: ImageViewModel public var eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(radioButton: RadioButtonModel, image: ImageViewModel, eyebrowHeadlineBodyLink:EyebrowHeadlineBodyLinkModel) { self.radioButton = radioButton self.image = image @@ -21,6 +29,10 @@ public class ListLeftVariableRadioButtonAndPaymentMethodModel: ListItemModel, Mo super.init() } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + public override func setDefaults() { super.setDefaults() if image.width == nil, image.height == nil { @@ -29,6 +41,10 @@ public class ListLeftVariableRadioButtonAndPaymentMethodModel: ListItemModel, Mo } } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case radioButton @@ -36,6 +52,10 @@ public class ListLeftVariableRadioButtonAndPaymentMethodModel: ListItemModel, Mo case eyebrowHeadlineBodyLink } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) radioButton = try typeContainer.decode(RadioButtonModel.self, forKey: .radioButton) From 313cab70b351b6b18ecc93400b64dd0af967f5e2 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 5 May 2020 17:52:01 -0400 Subject: [PATCH 08/10] changes for accessibility and formatting --- MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift | 2 +- ...ListLeftVariableRadioButtonAndPaymentMethod.swift | 12 +++++++++--- .../ListLeftVariableRadioButtonBodyText.swift | 11 ++++++++--- .../Atomic/Templates/MoleculeListCellProtocol.swift | 12 +++++------- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift index aa73e7b5..1ac28ded 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift @@ -20,7 +20,7 @@ import UIKit } } - public override var isSelected: Bool { + @objc public override var isSelected: Bool { didSet { radioModel?.state = isSelected updateAccessibilityLabel() diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index 489330b2..b0ac0e6a 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -14,11 +14,13 @@ import UIKit // MARK: - Outlets //----------------------------------------------------- - let radioButton = RadioButton(frame: .zero) + let radioButton = RadioButton() let leftImage = LoadImageView(pinnedEdges: .all) let eyebrowHeadlineBodyLink = EyebrowHeadlineBodyLink() var stack: Stack + private var observation: NSKeyValueObservation? = nil + //----------------------------------------------------- // MARK: - Initializers //----------------------------------------------------- @@ -46,11 +48,16 @@ import UIKit stack.restack() eyebrowHeadlineBodyLink.body.textColor = .mvmOrangeAA eyebrowHeadlineBodyLink.headline.styleBoldBodySmall(true) - + radioButton.isAccessibilityElement = false isAccessibilityElement = true updateAccessibilityLabel() accessibilityTraits = .button accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") + updateAccessibilityLabel() + + observation = observe(\.radioButton.isSelected, options: [.new]) { [weak self] _, _ in + self?.updateAccessibilityLabel() + } } open override func reset() { @@ -69,7 +76,6 @@ import UIKit radioButton.set(with: model.radioButton, delegateObject, additionalData) leftImage.set(with: model.image, delegateObject, additionalData) eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData) - updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index f1ac9637..5e9dd53d 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -18,6 +18,8 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { let headlineBody = HeadlineBody() var stack: Stack + private var observation: NSKeyValueObservation? = nil + //----------------------------------------------------- // MARK: - Initializers //----------------------------------------------------- @@ -43,9 +45,14 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { addMolecule(stack) stack.restack() isAccessibilityElement = true - updateAccessibilityLabel() + radioButton.isAccessibilityElement = false accessibilityTraits = .button accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") + updateAccessibilityLabel() + + observation = observe(\.radioButton.isSelected, options: [.new]) { [weak self] _, _ in + self?.updateAccessibilityLabel() + } } //---------------------------------------------------- @@ -59,7 +66,6 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { radioButton.set(with: model.radioButton, delegateObject, additionalData) headlineBody.set(with: model.headlineBody, delegateObject, additionalData) - updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -68,7 +74,6 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { radioButton.tapAction() - updateAccessibilityLabel() } func updateAccessibilityLabel() { diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListCellProtocol.swift b/MVMCoreUI/Atomic/Templates/MoleculeListCellProtocol.swift index b9cfc02f..46c9a0fa 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListCellProtocol.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListCellProtocol.swift @@ -21,12 +21,10 @@ public protocol MoleculeListCellProtocol: UITableViewCell { // Default implementation does nothing extension MoleculeListCellProtocol { - public func setLines(with model: LineModel?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { - } - public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - } - - func willDisplay() { - } + public func setLines(with model: LineModel?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { } + + public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { } + + func willDisplay() { } } From c61f6698065078038196c270b702e0c6fc398544 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 7 May 2020 17:11:43 -0400 Subject: [PATCH 09/10] text registered for init appearance. more acessiility to caret --- .../ListLeftVariableRadioButtonAndPaymentMethod.swift | 1 + .../List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift | 1 + MVMCoreUI/BaseClasses/TableViewCell.swift | 2 ++ 3 files changed, 4 insertions(+) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index b0ac0e6a..688f457c 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -76,6 +76,7 @@ import UIKit radioButton.set(with: model.radioButton, delegateObject, additionalData) leftImage.set(with: model.image, delegateObject, additionalData) eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index 5e9dd53d..d89604f9 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -66,6 +66,7 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { radioButton.set(with: model.radioButton, delegateObject, additionalData) headlineBody.set(with: model.headlineBody, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/BaseClasses/TableViewCell.swift b/MVMCoreUI/BaseClasses/TableViewCell.swift index b549b6d0..f07b1ee2 100644 --- a/MVMCoreUI/BaseClasses/TableViewCell.swift +++ b/MVMCoreUI/BaseClasses/TableViewCell.swift @@ -205,6 +205,8 @@ import UIKit let caret = CaretView(lineWidth: 1) caret.translatesAutoresizingMaskIntoConstraints = true caret.isAccessibilityElement = true + caret.accessibilityTraits = .button + caret.accessibilityLabel = "Caret," caret.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "AccTabHint") caret.size = .small(.vertical) if let size = caret.size?.dimensions() { From 111e4354662850770f40397428049615381e59c3 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 11 May 2020 16:14:42 -0400 Subject: [PATCH 10/10] delegate object for model decoding functions --- MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift | 2 +- MVMCoreUI/BaseControllers/ViewController.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift index 56b1a86c..04280042 100644 --- a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift @@ -8,7 +8,6 @@ import Foundation - public protocol TemplateProtocol: AnyObject { associatedtype TemplateModel: TemplateModelProtocol var templateModel: TemplateModel? { get set } @@ -19,6 +18,7 @@ public extension TemplateProtocol where Self: ViewController { guard let pageJSON = json else { return } let data = try JSONSerialization.data(withJSONObject: pageJSON) let decoder = JSONDecoder() + try decoder.add(delegateObject: delegateObjectIVar) let templateModel = try decoder.decode(TemplateModel.self, from: data) self.templateModel = templateModel self.pageModel = templateModel as? MVMControllerModelProtocol diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 315a0476..0872b0e6 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -17,7 +17,10 @@ import UIKit public var manager: (UIViewController & MVMCoreViewManagerProtocol)? /// A temporary iVar backer for delegateObject() until we change the protocol - public var delegateObjectIVar: MVMCoreUIDelegateObject? + public let delegateObjectIVar: MVMCoreUIDelegateObject = { + return MVMCoreUIDelegateObject.create(withDelegateForAll: self) + }() + public func delegateObject() -> DelegateObject? { return delegateObjectIVar } @@ -264,9 +267,6 @@ import UIKit // Presents from the bottom. modalPresentationStyle = MVMCoreGetterUtility.isOnIPad() ? .formSheet : .overCurrentContext - // Create the default delegate object. - delegateObjectIVar = MVMCoreUIDelegateObject.create(withDelegateForAll: self) - // Do some initial loading. if !initialLoadFinished { initialLoadFinished = true