one column and progress accessibililty logic

This commit is contained in:
Kevin G Christiano 2020-06-02 16:43:16 -04:00
parent b77c7c79e4
commit 7a9f9bd2c5
7 changed files with 235 additions and 32 deletions

View File

@ -8,20 +8,30 @@
import Foundation import Foundation
@objcMembers open class ProgressBar: UIProgressView, MVMCoreViewProtocol, MoleculeViewProtocol { @objcMembers open class ProgressBar: UIProgressView, MVMCoreViewProtocol, MoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
var progressBarModel: ProgressBarModel? var progressBarModel: ProgressBarModel?
var thickness: CGFloat = 8.0 { var thickness: CGFloat = 8.0 {
willSet(newValue) { willSet(newValue) {
heightAnchor.constraint(equalToConstant: newValue).isActive = true heightAnchor.constraint(equalToConstant: newValue).isActive = true
if progressBarModel?.roundedCorners ?? false { if progressBarModel?.roundedCorners ?? false {
layer.cornerRadius = newValue/2.0 layer.cornerRadius = newValue / 2.0
} else { } else {
progressViewStyle = .bar progressViewStyle = .bar
} }
} }
} }
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public override init(frame: CGRect) { public override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
setupView() setupView()
@ -37,41 +47,49 @@ import Foundation
setupView() setupView()
} }
// MARK: - MVMCoreViewProtocol //--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
public func setupView() { public func setupView() {
clipsToBounds = true clipsToBounds = true
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
thickness = 8 thickness = 8
progress = 0 progress = 0
progressTintColor = UIColor.mfCerulean() progressTintColor = .mfCerulean()
trackTintColor = UIColor.mfLightSilver() trackTintColor = .mvmCoolGray3
} }
public func updateView(_ size: CGFloat) { public func updateView(_ size: CGFloat) { }
}
//--------------------------------------------------
// MARK: - MVMCoreViewProtocol
//--------------------------------------------------
//MARK: - MoleculeViewProtocol
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard let progressBarModel = model as? ProgressBarModel else { return } guard let progressBarModel = model as? ProgressBarModel else { return }
self.progressBarModel = progressBarModel self.progressBarModel = progressBarModel
thickness = progressBarModel.thickness ?? 8 thickness = progressBarModel.thickness ?? 8
progress = Float((progressBarModel.percent)/100.0) progress = Float((progressBarModel.percent) / 100.0)
progressTintColor = progressBarModel.color.uiColor progressTintColor = progressBarModel.color.uiColor
if let backgroundColor = progressBarModel.backgroundColor { if let backgroundColor = progressBarModel.backgroundColor {
trackTintColor = backgroundColor.uiColor trackTintColor = backgroundColor.uiColor
} }
} }
public func reset() { public func reset() {
thickness = 8 thickness = 8
progress = 0 progress = 0
progressTintColor = UIColor.mfCerulean() progressTintColor = .mfCerulean()
trackTintColor = UIColor.mfLightSilver() trackTintColor = .mvmCoolGray3
} }
public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 8 return 8
} }
} }

View File

@ -7,15 +7,18 @@
// //
import Foundation import Foundation
@objcMembers open class ListProgressBarThin: TableViewCell { @objcMembers open class ListProgressBarThin: TableViewCell {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Outlets // MARK: - Outlets
//-------------------------------------------------- //--------------------------------------------------
public let progressBar = ProgressBar() public let progressBar = ProgressBar()
public let leftHeadline = Label.commonLabelB1(true) public let leftHeadline = Label.createLabelBoldBodySmall(true)
public let leftBody = Label.commonLabelB2(true) public let leftBody = Label.createLabelBoldBodySmall(true)
public let rightBar = Line() public let rightBar = Line()
public let rightLabel = Label.commonLabelB2(true) public let rightLabel = Label.createLabelBoldBodySmall(true)
private let barStackItem: StackItem private let barStackItem: StackItem
private let rightLabelStackItem: StackItem private let rightLabelStackItem: StackItem
public var labelStack: Stack<StackModel> public var labelStack: Stack<StackModel>
@ -25,6 +28,7 @@ import Foundation
//------------------------------------------------------ //------------------------------------------------------
// MARK: - Initializers // MARK: - Initializers
//------------------------------------------------------ //------------------------------------------------------
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
//vertical stack with leftHeadline, leftBody //vertical stack with leftHeadline, leftBody
labelStack = Stack<StackModel>.createStack(with: [leftHeadline, leftBody], axis: .vertical, spacing: 2) labelStack = Stack<StackModel>.createStack(with: [leftHeadline, leftBody], axis: .vertical, spacing: 2)
@ -34,7 +38,7 @@ import Foundation
rightLabelStackItem = StackItem(andContain: rightLabel) rightLabelStackItem = StackItem(andContain: rightLabel)
let horizontalStackItems = [StackItem(andContain: labelStack), barStackItem, rightLabelStackItem] let horizontalStackItems = [StackItem(andContain: labelStack), barStackItem, rightLabelStackItem]
let horizontalStackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .leading), StackItemModel(horizontalAlignment: .fill), StackItemModel(spacing: 5, horizontalAlignment: .fill)], let horizontalStackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .leading), StackItemModel(horizontalAlignment: .fill), StackItemModel(spacing: 5, horizontalAlignment: .fill)],
axis: .horizontal) axis: .horizontal)
horizontalStack = Stack<StackModel>(with: horizontalStackModel, stackItems: horizontalStackItems) horizontalStack = Stack<StackModel>(with: horizontalStackModel, stackItems: horizontalStackItems)
//stack with all components //stack with all components
@ -49,19 +53,23 @@ import Foundation
open override func alignAccessoryToHero() -> CGPoint? { open override func alignAccessoryToHero() -> CGPoint? {
// Ensures that the right items are centered with the arrow. // Ensures that the right items are centered with the arrow.
let heroCenter = super.alignAccessoryToHero() let heroCenter = super.alignAccessoryToHero()
if let heroCenter = heroCenter { if let heroCenter = heroCenter {
let convertedPoint = horizontalStack.convert(heroCenter, from: self) let convertedPoint = horizontalStack.convert(heroCenter, from: self)
barStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - horizontalStack.bounds.midY barStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - horizontalStack.bounds.midY
rightLabelStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - horizontalStack.bounds.midY rightLabelStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - horizontalStack.bounds.midY
} }
return heroCenter return heroCenter
} }
//------------------------------------------------------- //-------------------------------------------------------
// MARK: - View Lifecycle // MARK: - Lifecycle
//------------------------------------------------------- //-------------------------------------------------------
open override func setupView() { open override func setupView() {
super.setupView() super.setupView()
rightBar.widthAnchor.constraint(equalToConstant: 20).isActive = true rightBar.widthAnchor.constraint(equalToConstant: 20).isActive = true
rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal)
rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal) rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal)
@ -70,19 +78,24 @@ import Foundation
stack.restack() stack.restack()
horizontalStack.restack() horizontalStack.restack()
labelStack.restack() labelStack.restack()
isAccessibilityElement = true
updateAccessibilityLabel()
} }
//------------------------------------------------------ //------------------------------------------------------
// MARK: - Molecule // 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) super.set(with: model, delegateObject, additionalData)
guard let model = model as? ListProgressBarThinModel else { return } guard let model = model as? ListProgressBarThinModel else { return }
labelStack.updateContainedMolecules(with: [model.leftHeadline,
model.leftBody], delegateObject, additionalData) labelStack.updateContainedMolecules(with: [model.leftHeadline, model.leftBody], delegateObject, additionalData)
progressBar.set(with: model.progressBar, delegateObject, additionalData) progressBar.set(with: model.progressBar, delegateObject, additionalData)
rightBar.set(with: model.rightBar, delegateObject, additionalData) rightBar.set(with: model.rightBar, delegateObject, additionalData)
rightLabel.set(with: model.rightLabel, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData)
updateAccessibilityLabel()
} }
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
@ -96,4 +109,31 @@ import Foundation
rightLabel.styleB2(true) rightLabel.styleB2(true)
rightBar.setStyle(.medium) rightBar.setStyle(.medium)
} }
//------------------------------------------------------
// MARK: - Accessibility
//------------------------------------------------------
func updateAccessibilityLabel() {
var message = ""
if let leftHeadlineText = leftHeadline.text {
message += leftHeadlineText + ", "
}
if let leftBodyText = leftBody.text {
message += leftBodyText + ", "
}
if let progressLabel = progressBar.accessibilityLabel, let progressValue = progressBar.accessibilityValue {
message += progressLabel + ", " + progressValue + ", "
}
if let rightLabelText = rightLabel.text {
message += rightLabelText + ", "
}
accessibilityLabel = message
}
} }

View File

@ -7,7 +7,13 @@
// //
import Foundation import Foundation
public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier = "listPrgBarThin" public static var identifier = "listPrgBarThin"
public var progressBar: ProgressBarModel public var progressBar: ProgressBarModel
public var leftHeadline: LabelModel public var leftHeadline: LabelModel
@ -15,6 +21,10 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol {
public var rightBar: LineModel public var rightBar: LineModel
public var rightLabel: LabelModel public var rightLabel: LabelModel
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel? = nil, rightBar: LineModel, rightLabel: LabelModel) { public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel? = nil, rightBar: LineModel, rightLabel: LabelModel) {
self.progressBar = progressBar self.progressBar = progressBar
self.leftHeadline = leftHeadline self.leftHeadline = leftHeadline
@ -24,15 +34,26 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol {
super.init() super.init()
} }
//--------------------------------------------------
// MARK: - Method
//--------------------------------------------------
override public func setDefaults() { override public func setDefaults() {
super.setDefaults() super.setDefaults()
rightBar.type = .medium rightBar.type = .medium
if rightBar.backgroundColor == nil { if rightBar.backgroundColor == nil {
rightBar.backgroundColor = Color(uiColor: .gray) rightBar.backgroundColor = Color(uiColor: .gray)
} }
leftHeadline.hero = 0 leftHeadline.hero = 0
} }
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName case moleculeName
case progressBar case progressBar
@ -42,6 +63,10 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol {
case rightLabel case rightLabel
} }
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
public required init(from decoder: Decoder) throws { public required init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
progressBar = try typeContainer.decode(ProgressBarModel.self, forKey:.progressBar) progressBar = try typeContainer.decode(ProgressBarModel.self, forKey:.progressBar)

View File

@ -43,17 +43,17 @@ import Foundation
super.setupView() super.setupView()
addMolecule(stack) addMolecule(stack)
stack.restack() stack.restack()
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) super.set(with: model, delegateObject, additionalData)
guard let model = model as? ListOneColumnFullWidthTextAllTextAndLinksModel else { return } guard let model = model as? ListOneColumnFullWidthTextAllTextAndLinksModel else { return }
stack.updateContainedMolecules(with: [model.eyebrow,
model.headline, stack.updateContainedMolecules(with: [model.eyebrow, model.headline, model.subHeadline, model.body, model.link],
model.subHeadline,
model.body,
model.link],
delegateObject, additionalData) delegateObject, additionalData)
updateAccessibilityLabel()
} }
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
@ -67,4 +67,60 @@ import Foundation
subHeadline.styleBoldBodySmall(true) subHeadline.styleBoldBodySmall(true)
body.styleRegularBodySmall(true) body.styleRegularBodySmall(true)
} }
func updateAccessibilityLabel() {
var message = ""
if let eyebrowLabel = eyebrow.text {
message += eyebrowLabel + ", "
}
if let headlineLabel = headline.text {
message += headlineLabel + ", "
}
if let headlineLabel = headline.text {
message += headlineLabel + ", "
}
if let bodyLabel = body.text {
message += bodyLabel
}
let linkShowing = link.titleLabel?.text?.count ?? 0 > 0
isAccessibilityElement = !linkShowing
link.isAccessibilityElement = linkShowing
if !linkShowing {
// Make whole cell focusable if no link.
accessibilityLabel = message
} else {
// Allow only radio button and link to be focused on.
var elements: [UIView] = []
if let eyeBrowText = eyebrow.text, !eyeBrowText.isEmpty {
elements.append(eyebrow)
}
if let headlineText = headline.text, !headlineText.isEmpty {
elements.append(headline)
}
if let subHeadlineText = subHeadline.text, !subHeadlineText.isEmpty {
elements.append(subHeadline)
}
if let bodyText = body.text, !bodyText.isEmpty {
elements.append(body)
}
if linkShowing {
elements.append(link)
}
accessibilityElements = elements
}
}
} }

View File

@ -8,7 +8,12 @@
import Foundation import Foundation
public class ListOneColumnFullWidthTextAllTextAndLinksModel: ListItemModel, MoleculeModelProtocol { public class ListOneColumnFullWidthTextAllTextAndLinksModel: ListItemModel, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "list1CTxt" public static var identifier: String = "list1CTxt"
public var eyebrow: LabelModel? public var eyebrow: LabelModel?
public var headline : LabelModel? public var headline : LabelModel?
@ -16,6 +21,10 @@ public class ListOneColumnFullWidthTextAllTextAndLinksModel: ListItemModel, Mole
public var body: LabelModel? public var body: LabelModel?
public var link : LinkModel? public var link : LinkModel?
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(eyebrow: LabelModel? = nil, headline: LabelModel? = nil, subHeadline: LabelModel? = nil, body: LabelModel? = nil, link: LinkModel? = nil) { public init(eyebrow: LabelModel? = nil, headline: LabelModel? = nil, subHeadline: LabelModel? = nil, body: LabelModel? = nil, link: LinkModel? = nil) {
self.eyebrow = eyebrow self.eyebrow = eyebrow
self.headline = headline self.headline = headline
@ -25,6 +34,10 @@ public class ListOneColumnFullWidthTextAllTextAndLinksModel: ListItemModel, Mole
super.init() super.init()
} }
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName case moleculeName
case eyebrow case eyebrow
@ -34,6 +47,10 @@ public class ListOneColumnFullWidthTextAllTextAndLinksModel: ListItemModel, Mole
case link case link
} }
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow) eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow)

View File

@ -8,28 +8,55 @@
import Foundation import Foundation
@objcMembers open class ListOneColumnFullWidthTextBodyText: TableViewCell {
@objcMembers open class ListOneColumnFullWidthTextBodyText: TableViewCell {
//----------------------------------------------------- //-----------------------------------------------------
// MARK: - Outlets // MARK: - Outlets
//----------------------------------------------------- //-----------------------------------------------------
public var headlineBody = HeadlineBody(frame: .zero)
public var headlineBody = HeadlineBody()
//----------------------------------------------------- //-----------------------------------------------------
// MARK: - View Lifecycle // MARK: - Lifecycle
//----------------------------------------------------- //-----------------------------------------------------
override open func setupView() { override open func setupView() {
super.setupView() super.setupView()
addMolecule(headlineBody) addMolecule(headlineBody)
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) super.set(with: model, delegateObject, additionalData)
guard let model = model as? ListOneColumnFullWidthTextBodyTextModel else { return } guard let model = model as? ListOneColumnFullWidthTextBodyTextModel else { return }
headlineBody.set(with: model.headlineBody, delegateObject, additionalData) headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
updateAccessibilityLabel()
} }
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 90 return 90
} }
//-----------------------------------------------------
// MARK: - Accessibility
//-----------------------------------------------------
func updateAccessibilityLabel() {
var message = ""
if let headlineLabel = headlineBody.headlineLabel.text {
message += headlineLabel + ", "
}
if let messageLabel = headlineBody.messageLabel.text {
message += messageLabel
}
accessibilityLabel = message
}
} }

View File

@ -8,26 +8,46 @@
import Foundation import Foundation
public class ListOneColumnFullWidthTextBodyTextModel: ListItemModel, MoleculeModelProtocol { public class ListOneColumnFullWidthTextBodyTextModel: ListItemModel, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "list1CFWBdy" public static var identifier: String = "list1CFWBdy"
public var headlineBody: HeadlineBodyModel public var headlineBody: HeadlineBodyModel
//--------------------------------------------------
// MARK: - Initializier
//--------------------------------------------------
public init(headlineBody: HeadlineBodyModel) { public init(headlineBody: HeadlineBodyModel) {
self.headlineBody = headlineBody self.headlineBody = headlineBody
super.init() super.init()
} }
// Defaults to set //--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
override public func setDefaults() { override public func setDefaults() {
super.setDefaults() super.setDefaults()
headlineBody.style = .item headlineBody.style = .item
} }
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName case moleculeName
case headlineBody case headlineBody
} }
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody)