changes for accessibility. formatting and spacing

This commit is contained in:
Kevin G Christiano 2020-09-09 15:41:28 -04:00
parent 5326a3afd6
commit 5aee74282b
21 changed files with 217 additions and 69 deletions

View File

@ -51,6 +51,7 @@ import UIKit
guard let model = model as? LinkModel else { return } guard let model = model as? LinkModel else { return }
setTitle(model.title, for: .normal) setTitle(model.title, for: .normal)
accessibilityLabel = model.title
setTitleColor((model.inverted ? model.enabledColor_inverted : model.enabledColor).uiColor, for: .normal) setTitleColor((model.inverted ? model.enabledColor_inverted : model.enabledColor).uiColor, for: .normal)
setTitleColor((model.inverted ? model.disabledColor_inverted : model.disabledColor).uiColor, for: .disabled) setTitleColor((model.inverted ? model.disabledColor_inverted : model.disabledColor).uiColor, for: .disabled)
isEnabled = model.enabled isEnabled = model.enabled

View File

@ -6,9 +6,12 @@
// Copyright © 2019 Verizon Wireless. All rights reserved. // Copyright © 2019 Verizon Wireless. All rights reserved.
// //
import Foundation
@objcMembers public class ImageViewModel: MoleculeModelProtocol { @objcMembers public class ImageViewModel: MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "image" public static var identifier: String = "image"
public var backgroundColor: Color? public var backgroundColor: Color?
public var moleculeName: String = ImageViewModel.identifier public var moleculeName: String = ImageViewModel.identifier
@ -22,6 +25,10 @@ import Foundation
public var localBundle: Bundle? public var localBundle: Bundle?
public var cornerRadius: CGFloat? public var cornerRadius: CGFloat?
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(image: String, imageFormat: String? = nil, width: CGFloat? = nil, height: CGFloat? = nil) { public init(image: String, imageFormat: String? = nil, width: CGFloat? = nil, height: CGFloat? = nil) {
self.image = image self.image = image
self.imageFormat = imageFormat self.imageFormat = imageFormat
@ -29,6 +36,10 @@ import Foundation
self.height = height self.height = height
} }
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName case moleculeName
case backgroundColor case backgroundColor

View File

@ -249,6 +249,7 @@ public typealias ActionBlock = () -> ()
attributedText = nil attributedText = nil
originalAttributedString = nil originalAttributedString = nil
text = nil
text = labelModel.text text = labelModel.text
hero = labelModel.hero hero = labelModel.hero
Label.setLabel(self, withHTML: labelModel.html) Label.setLabel(self, withHTML: labelModel.html)

View File

@ -6,8 +6,6 @@
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import Foundation
@objcMembers open class ListDeviceComplexButtonSmall: TableViewCell { @objcMembers open class ListDeviceComplexButtonSmall: TableViewCell {
//-------------------------------------------------- //--------------------------------------------------
@ -19,7 +17,7 @@ import Foundation
public let headline = Label(fontStyle: .BoldTitleMedium) public let headline = Label(fontStyle: .BoldTitleMedium)
public let body = Label(fontStyle: .RegularBodySmall) public let body = Label(fontStyle: .RegularBodySmall)
public let body2 = Label(fontStyle: .RegularBodySmall) public let body2 = Label(fontStyle: .RegularBodySmall)
public let button = PillButton(frame: .zero) public let button = PillButton()
public let rightImageView = LoadImageView() public let rightImageView = LoadImageView()
public var stack: Stack<StackModel> public var stack: Stack<StackModel>
@ -99,6 +97,7 @@ import Foundation
//-------------------------------------------------- //--------------------------------------------------
func getAccessibilityMessage() -> String? { func getAccessibilityMessage() -> String? {
var message = "" var message = ""
if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty { if let eyebrowText = eyebrow.text, !eyebrowText.isEmpty {
message += eyebrowText + ", " message += eyebrowText + ", "
@ -119,10 +118,12 @@ import Foundation
if let rightImageViewText = rightImageView.imageView.accessibilityLabel, !rightImageViewText.isEmpty { if let rightImageViewText = rightImageView.imageView.accessibilityLabel, !rightImageViewText.isEmpty {
message += rightImageViewText message += rightImageViewText
} }
return message.count > 0 ? message : nil return message.count > 0 ? message : nil
} }
func updateAccessibilityLabel() { func updateAccessibilityLabel() {
if let accessoryView = accessoryView { if let accessoryView = accessoryView {
// Both caret and button. Read all content on caret. // Both caret and button. Read all content on caret.
isAccessibilityElement = false isAccessibilityElement = false

View File

@ -8,6 +8,7 @@
import UIKit import UIKit
@objcMembers open class TwoButtonView: View, MVMCoreUIViewConstrainingProtocol { @objcMembers open class TwoButtonView: View, MVMCoreUIViewConstrainingProtocol {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
@ -60,6 +61,7 @@ import UIKit
super.setupView() super.setupView()
stack.translatesAutoresizingMaskIntoConstraints = false stack.translatesAutoresizingMaskIntoConstraints = false
isAccessibilityElement = false
addSubview(stack) addSubview(stack)
stack.addArrangedSubview(secondaryButton) stack.addArrangedSubview(secondaryButton)
stack.addArrangedSubview(primaryButton) stack.addArrangedSubview(primaryButton)
@ -84,6 +86,8 @@ import UIKit
if secondaryButton.superview != nil { if secondaryButton.superview != nil {
equalWidthConstraint?.isActive = true equalWidthConstraint?.isActive = true
} }
primaryButton.isAccessibilityElement = true
} }
public func showSecondaryButton() { public func showSecondaryButton() {
@ -96,6 +100,8 @@ import UIKit
if primaryButton.superview != nil { if primaryButton.superview != nil {
equalWidthConstraint?.isActive = true equalWidthConstraint?.isActive = true
} }
secondaryButton.isAccessibilityElement = true
} }
public func hidePrimaryButton() { public func hidePrimaryButton() {
@ -105,6 +111,7 @@ import UIKit
primaryButton.isHidden = true primaryButton.isHidden = true
} }
primaryButton.isAccessibilityElement = false
equalWidthConstraint?.isActive = false equalWidthConstraint?.isActive = false
} }
@ -115,6 +122,7 @@ import UIKit
secondaryButton.isHidden = true secondaryButton.isHidden = true
} }
secondaryButton.isAccessibilityElement = false
equalWidthConstraint?.isActive = false equalWidthConstraint?.isActive = false
} }

View File

@ -6,9 +6,12 @@
// Copyright © 2019 Suresh, Kamlesh. All rights reserved. // Copyright © 2019 Suresh, Kamlesh. All rights reserved.
// //
import Foundation
@objcMembers public class MoleculeStackItemModel: MoleculeContainerModel, StackItemModelProtocol { @objcMembers public class MoleculeStackItemModel: MoleculeContainerModel, StackItemModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public override class var identifier: String { public override class var identifier: String {
return "stackItem" return "stackItem"
} }
@ -16,16 +19,28 @@ import Foundation
public var percent: Int? public var percent: Int?
public var gone: Bool = false public var gone: Bool = false
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case spacing case spacing
case percent case percent
case gone case gone
} }
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public override init(with moleculeModel: MoleculeModelProtocol) { public override init(with moleculeModel: MoleculeModelProtocol) {
super.init(with: moleculeModel) super.init(with: moleculeModel)
} }
//--------------------------------------------------
// 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)
spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing)
@ -35,7 +50,7 @@ import Foundation
} }
try super.init(from: decoder) try super.init(from: decoder)
} }
public override func encode(to encoder: Encoder) throws { public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder) try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)

View File

@ -6,7 +6,6 @@
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import Foundation
open class StackItem: Container { open class StackItem: Container {
var stackItemModel: StackItemModel? { var stackItemModel: StackItemModel? {

View File

@ -8,14 +8,22 @@
import UIKit import UIKit
public class MoleculeHeaderView: MoleculeContainer { public class MoleculeHeaderView: MoleculeContainer {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
var line = Line() var line = Line()
var headerModel: MoleculeHeaderModel? { var headerModel: MoleculeHeaderModel? {
get { return model as? MoleculeHeaderModel } get { return model as? MoleculeHeaderModel }
} }
//--------------------------------------------------
// MARK: - MVMCoreViewProtocol // MARK: - MVMCoreViewProtocol
//--------------------------------------------------
open override func updateView(_ size: CGFloat) { open override func updateView(_ size: CGFloat) {
super.updateView(size) super.updateView(size)
line.updateView(size) line.updateView(size)
@ -30,16 +38,16 @@ public class MoleculeHeaderView: MoleculeContainer {
NSLayoutConstraint.pinViewRight(toSuperview: line, useMargins: true, constant: 0).isActive = true NSLayoutConstraint.pinViewRight(toSuperview: line, useMargins: true, constant: 0).isActive = true
} }
// MARK: - MoleculeViewProtocol
open override func reset() { open override func reset() {
super.reset() super.reset()
line.setStyle(.heavy) line.setStyle(.heavy)
} }
// MARK: - MoleculeViewProtocol
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 headerModel = headerModel else { return } guard let headerModel = headerModel else { return }
if let lineModel = headerModel.line { if let lineModel = headerModel.line {
line.set(with: lineModel, delegateObject, additionalData) line.set(with: lineModel, delegateObject, additionalData)
} }

View File

@ -8,6 +8,7 @@
import UIKit import UIKit
open class MoleculeContainer: Container { open class MoleculeContainer: Container {
/// Can be overriden to change how the molecule is added to the hierarchy. /// Can be overriden to change how the molecule is added to the hierarchy.
@ -16,6 +17,7 @@ open class MoleculeContainer: Container {
} }
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
if let casteModel = model as? MoleculeContainerModelProtocol { if let casteModel = model as? MoleculeContainerModelProtocol {
if view != nil { if view != nil {
(view as? MoleculeViewProtocol)?.set(with: casteModel.molecule, delegateObject, additionalData) (view as? MoleculeViewProtocol)?.set(with: casteModel.molecule, delegateObject, additionalData)
@ -29,26 +31,32 @@ open class MoleculeContainer: Container {
} }
public override static func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { public override static func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
guard let containerModel = model as? MoleculeContainerModelProtocol, guard let containerModel = model as? MoleculeContainerModelProtocol,
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule), let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule),
let moleculeName = moleculeClass.nameForReuse(with: containerModel.molecule, delegateObject) else { let moleculeName = moleculeClass.nameForReuse(with: containerModel.molecule, delegateObject)
return "\(model.moleculeName)<>" else { return "\(model.moleculeName)<>" }
}
return "\(model.moleculeName)<\(moleculeName)>" return "\(model.moleculeName)<\(moleculeName)>"
} }
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
guard let containerModel = model as? MoleculeContainerModelProtocol else { return 0 } guard let containerModel = model as? MoleculeContainerModelProtocol else { return 0 }
guard let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule), guard let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule),
let moleculeHeight = moleculeClass.estimatedHeight(with: containerModel.molecule, delegateObject) else { let moleculeHeight = moleculeClass.estimatedHeight(with: containerModel.molecule, delegateObject)
return (containerModel.topPadding ?? 0) + (containerModel.bottomPadding ?? 0) else { return (containerModel.topPadding ?? 0) + (containerModel.bottomPadding ?? 0) }
}
return moleculeHeight + (containerModel.topPadding ?? 0) + (containerModel.bottomPadding ?? 0) return moleculeHeight + (containerModel.topPadding ?? 0) + (containerModel.bottomPadding ?? 0)
} }
public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? { public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
guard let containerModel = model as? MoleculeContainerModelProtocol, guard let containerModel = model as? MoleculeContainerModelProtocol,
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule) else { return nil } let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(containerModel.molecule)
else { return nil }
return moleculeClass.requiredModules(with: containerModel.molecule, delegateObject, error: error) return moleculeClass.requiredModules(with: containerModel.molecule, delegateObject, error: error)
} }
} }

View File

@ -8,11 +8,15 @@
import UIKit import UIKit
// This class is only temporarily necessary. Eventually we will have initWithModel instad of just init for moleculeviews, which will remove this need. // 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 { 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, guard let model = model as? StackModelProtocol,
let molcules = model.molecules as? [MoleculeStackItemModel] else { return } let molcules = model.molecules as? [MoleculeStackItemModel]
else { return }
for stackItemModel in molcules { for stackItemModel in molcules {
guard let stringAndMoleculeModel = stackItemModel.molecule as? StringAndMoleculeModel, guard let stringAndMoleculeModel = stackItemModel.molecule as? StringAndMoleculeModel,
let molecule = MoleculeObjectMapping.shared()?.createMolecule(stringAndMoleculeModel.molecule, delegateObject: delegateObject let molecule = MoleculeObjectMapping.shared()?.createMolecule(stringAndMoleculeModel.molecule, delegateObject: delegateObject

View File

@ -6,9 +6,9 @@
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import Foundation
open class StringAndMoleculeView: View { open class StringAndMoleculeView: View {
var label = Label(fontStyle: .RegularBodySmall) var label = Label(fontStyle: .RegularBodySmall)
var molecule: MoleculeViewProtocol var molecule: MoleculeViewProtocol
@ -38,11 +38,9 @@ open class StringAndMoleculeView: View {
override public func setupView() { override public func setupView() {
super.setupView() super.setupView()
guard subviews.count == 0 else {
return
}
translatesAutoresizingMaskIntoConstraints = false guard subviews.count == 0 else { return }
addSubview(label) addSubview(label)
addSubview(molecule) addSubview(molecule)
@ -75,7 +73,7 @@ open class StringAndMoleculeView: View {
molecule.reset() molecule.reset()
} }
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { public 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? StringAndMoleculeModel else { return } guard let model = model as? StringAndMoleculeModel else { return }
label.text = model.string label.text = model.string
@ -85,7 +83,7 @@ open class StringAndMoleculeView: View {
func updateLeftViewWidthConstraint(_ percent: CGFloat) { func updateLeftViewWidthConstraint(_ percent: CGFloat) {
percentage = percent percentage = percent
leftWidthConstraint?.isActive = false leftWidthConstraint?.isActive = false
leftWidthConstraint = label.widthAnchor.constraint(equalTo: widthAnchor, multiplier: CGFloat(percent/100), constant: 0) leftWidthConstraint = label.widthAnchor.constraint(equalTo: widthAnchor, multiplier: CGFloat(percent / 100), constant: 0)
leftWidthConstraint?.isActive = true leftWidthConstraint?.isActive = true
} }
} }

View File

@ -9,12 +9,16 @@
import UIKit import UIKit
open class MoleculeStackView: Stack<StackModel> { open class MoleculeStackView: Stack<StackModel> {
var previousModel: MoleculeModelProtocol? var previousModel: MoleculeModelProtocol?
/// Convenience function, adds a molecule to a MoleculeStackItem to the MoleculeStack /// Convenience function, adds a molecule to a MoleculeStackItem to the MoleculeStack
func setup(with views: [View], lastItem: Bool) { func setup(with views: [View], lastItem: Bool) {
var models: [MoleculeStackItemModel] = [] var models: [MoleculeStackItemModel] = []
for view in views { for view in views {
guard let model = view.model else { return } guard let model = view.model else { return }
let stackItemModel = MoleculeStackItemModel(with: model) let stackItemModel = MoleculeStackItemModel(with: model)
@ -22,20 +26,22 @@ open class MoleculeStackView: Stack<StackModel> {
stackItems.append(stackItem) stackItems.append(stackItem)
models.append(stackItemModel) models.append(stackItemModel)
} }
if let stackModel = stackModel { if let stackModel = stackModel {
stackModel.molecules = models stackModel.molecules = models
} else { } else {
model = StackModel(molecules: models) model = StackModel(molecules: models)
} }
restack() restack()
} }
// MARK: - Adding to stack // MARK: - Adding to stack
/// Can be subclassed to create views when we get stack item models and have no views yet /// Can be subclassed to create views when we get stack item models and have no views yet
open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard let stackItemModels = stackModel?.molecules else { return } guard let stackItemModels = stackModel?.molecules else { return }
for model in stackItemModels { for model in stackItemModels {
if let stackItem = MoleculeObjectMapping.shared()?.createMolecule(model, delegateObject: delegateObject, additionalData: additionalData) as? MoleculeStackItem { if let stackItem = MoleculeObjectMapping.shared()?.createMolecule(model, delegateObject: delegateObject, additionalData: additionalData) as? MoleculeStackItem {
stackItems.append(stackItem) stackItems.append(stackItem)
@ -43,8 +49,8 @@ open class MoleculeStackView: Stack<StackModel> {
} }
} }
open override func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { open override func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
// If the items in the stack are different, clear them, create new ones. // If the items in the stack are different, clear them, create new ones.
if (previousModel == nil) || Self.nameForReuse(with: previousModel!, delegateObject) != Self.nameForReuse(with: model, delegateObject) { if (previousModel == nil) || Self.nameForReuse(with: previousModel!, delegateObject) != Self.nameForReuse(with: model, delegateObject) {
removeAllItemViews() removeAllItemViews()
stackItems = [] stackItems = []

View File

@ -6,8 +6,6 @@
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import Foundation
open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProtocol) { open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProtocol) {
//-------------------------------------------------- //--------------------------------------------------
@ -16,6 +14,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
open var contentView: UIView = MVMCoreUICommonViewsUtility.commonView() open var contentView: UIView = MVMCoreUICommonViewsUtility.commonView()
open var stackItems: [UIView] = [] open var stackItems: [UIView] = []
var didSetAcessibilityElements = false
open var stackModel: T? { open var stackModel: T? {
get { return model as? T } get { return model as? T }
@ -24,7 +23,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Helpers // MARK: - Helpers
//-------------------------------------------------- //--------------------------------------------------
open func pinView(_ view: UIView, toView: UIView, attribute: NSLayoutConstraint.Attribute, relation: NSLayoutConstraint.Relation, priority: UILayoutPriority, constant: CGFloat) { open func pinView(_ view: UIView, toView: UIView, attribute: NSLayoutConstraint.Attribute, relation: NSLayoutConstraint.Relation, priority: UILayoutPriority, constant: CGFloat) {
let constraint = NSLayoutConstraint(item: view, attribute: attribute, relatedBy: relation, toItem: toView, attribute: attribute, multiplier: 1.0, constant: constant) let constraint = NSLayoutConstraint(item: view, attribute: attribute, relatedBy: relation, toItem: toView, attribute: attribute, multiplier: 1.0, constant: constant)
@ -34,8 +33,11 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
/// Restacks the existing items. /// Restacks the existing items.
open func restack() { open func restack() {
removeAllItemViews() removeAllItemViews()
guard let stackModel = stackModel else { return } guard let stackModel = stackModel else { return }
let stackItems = self.stackItems let stackItems = self.stackItems
self.stackItems = [] self.stackItems = []
let lastItemIndex = stackModel.molecules.lastIndex { !$0.gone } let lastItemIndex = stackModel.molecules.lastIndex { !$0.gone }
@ -46,13 +48,24 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
addView(view, stackModel.molecules[index], totalSpacing: totalSpace, lastItem: lastItemIndex == index) addView(view, stackModel.molecules[index], totalSpacing: totalSpace, lastItem: lastItemIndex == index)
} }
// setAccessibilityElements()
}
open func setAccessibilityElements() {
guard !didSetAcessibilityElements,
let stackModel = stackModel
else { return }
isAccessibilityElement = false isAccessibilityElement = false
var accessibleViews: [Any] = [] var accessibleViews: [Any] = []
for (index, view) in stackItems.enumerated() where !stackModel.molecules[index].gone { for (index, view) in stackItems.enumerated() where !stackModel.molecules[index].gone {
accessibleViews.append(view) accessibleViews.append(view)
} }
accessibilityElements = accessibleViews accessibilityElements = accessibleViews
didSetAcessibilityElements = true
} }
/// Removes all stack items views from the view. /// Removes all stack items views from the view.
@ -62,6 +75,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
/// A convenience function for when the stackItems are containers and we want to update them based on the contained molecules models. If model is nil, stackItem is set to gone. Restacks if necessary. /// A convenience function for when the stackItems are containers and we want to update them based on the contained molecules models. If model is nil, stackItem is set to gone. Restacks if necessary.
open func updateContainedMolecules(with models: [MoleculeModelProtocol?], _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { open func updateContainedMolecules(with models: [MoleculeModelProtocol?], _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard var stackModel = stackModel else { return } guard var stackModel = stackModel else { return }
var needsRestack = false var needsRestack = false
@ -90,7 +104,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializers // MARK: - Initializers
//-------------------------------------------------- //--------------------------------------------------
public override init(frame: CGRect) { public override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
} }
@ -114,12 +128,15 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
/// Returns a Stack created with a StackModel and StackItems containing the passed in views. /// Returns a Stack created with a StackModel and StackItems containing the passed in views.
public static func createStack(with views: [UIView], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) -> Stack<StackModel> { public static func createStack(with views: [UIView], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) -> Stack<StackModel> {
var items: [StackItem] = [] var items: [StackItem] = []
var models: [StackItemModel] = [] var models: [StackItemModel] = []
for view in views { for view in views {
items.append(StackItem(andContain: view)) items.append(StackItem(andContain: view))
models.append(StackItemModel()) models.append(StackItemModel())
} }
let model = StackModel(molecules: models, axis: axis, spacing: spacing) let model = StackModel(molecules: models, axis: axis, spacing: spacing)
return Stack<StackModel>(with: model, stackItems: items) return Stack<StackModel>(with: model, stackItems: items)
} }
@ -128,10 +145,12 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
public static func createStack(with viewModels:[(view: UIView, model: StackItemModel)], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) -> Stack<StackModel> { public static func createStack(with viewModels:[(view: UIView, model: StackItemModel)], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) -> Stack<StackModel> {
var stackItems: [StackItem] = [] var stackItems: [StackItem] = []
var models: [StackItemModel] = [] var models: [StackItemModel] = []
for item in viewModels { for item in viewModels {
stackItems.append(StackItem(andContain: item.view)) stackItems.append(StackItem(andContain: item.view))
models.append(item.model) models.append(item.model)
} }
let model = StackModel(molecules: models, axis: axis, spacing: spacing) let model = StackModel(molecules: models, axis: axis, spacing: spacing)
return Stack<StackModel>(with: model, stackItems: stackItems) return Stack<StackModel>(with: model, stackItems: stackItems)
} }
@ -139,10 +158,12 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
//-------------------------------------------------- //--------------------------------------------------
// MARK: - MFViewProtocol // MARK: - MFViewProtocol
//-------------------------------------------------- //--------------------------------------------------
open override func setupView() { open override func setupView() {
super.setupView() super.setupView()
guard contentView.superview == nil else { return } guard contentView.superview == nil else { return }
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0) MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .clear backgroundColor = .clear
@ -162,7 +183,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
//-------------------------------------------------- //--------------------------------------------------
// MARK: - MoleculeViewProtocol // MARK: - MoleculeViewProtocol
//-------------------------------------------------- //--------------------------------------------------
open override func reset() { open override func reset() {
super.reset() super.reset()
backgroundColor = .clear backgroundColor = .clear
@ -217,13 +238,16 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
} }
open override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? { open override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
guard let model = model as? T else { return nil } guard let model = model as? T else { return nil }
var modules: [String] = [] var modules: [String] = []
for case let item in model.molecules { for case let item in model.molecules {
if let modulesForMolecule = (MoleculeObjectMapping.shared()?.getMoleculeClass(item))?.requiredModules(with: item, delegateObject, error: error) { if let modulesForMolecule = (MoleculeObjectMapping.shared()?.getMoleculeClass(item))?.requiredModules(with: item, delegateObject, error: error) {
modules += modulesForMolecule modules += modulesForMolecule
} }
} }
return modules.count > 0 ? modules : nil return modules.count > 0 ? modules : nil
} }
@ -233,7 +257,9 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
/// Can be subclassed to set stack items with model when we already have views /// Can be subclassed to set stack items with model when we already have views
open func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { open func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard let models = stackModel?.molecules else { return } guard let models = stackModel?.molecules else { return }
for (index, element) in models.enumerated() { for (index, element) in models.enumerated() {
(stackItems[index] as? MoleculeViewProtocol)?.set(with: element, delegateObject, additionalData) (stackItems[index] as? MoleculeViewProtocol)?.set(with: element, delegateObject, additionalData)
} }
@ -244,31 +270,39 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
//-------------------------------------------------- //--------------------------------------------------
/// Sets the stack with StackItems containing the passed in views and creates a StackModel with StackItems. /// Sets the stack with StackItems containing the passed in views and creates a StackModel with StackItems.
open func setAndCreateModel(with views: [UIView]) { open func setAndCreateModel(with views: [UIView]) {
var stackItems: [StackItem] = [] var stackItems: [StackItem] = []
var models: [StackItemModel] = [] var models: [StackItemModel] = []
for view in views { for view in views {
stackItems.append(StackItem(andContain: view)) stackItems.append(StackItem(andContain: view))
models.append(StackItemModel()) models.append(StackItemModel())
} }
self.stackItems = stackItems self.stackItems = stackItems
model = StackModel(molecules: models) model = StackModel(molecules: models)
} }
/// Sets the stack with StackItems containing the passed in views and sets the StackModel with models. /// Sets the stack with StackItems containing the passed in views and sets the StackModel with models.
open func set(with viewModels:[(view: UIView, model: StackItemModel)]) { open func set(with viewModels:[(view: UIView, model: StackItemModel)]) {
guard var stackModel = self.stackModel else { return } guard var stackModel = self.stackModel else { return }
var stackItems: [StackItem] = [] var stackItems: [StackItem] = []
var models: [StackItemModel] = [] var models: [StackItemModel] = []
for item in viewModels { for item in viewModels {
stackItems.append(StackItem(andContain: item.view)) stackItems.append(StackItem(andContain: item.view))
models.append(item.model) models.append(item.model)
} }
stackModel.molecules = models stackModel.molecules = models
self.stackItems = stackItems self.stackItems = stackItems
} }
/// Gets the percent modifier. This value is used to help properly calculate percent for stack items when spacing is involved. /// Gets the percent modifier. This value is used to help properly calculate percent for stack items when spacing is involved.
private func getTotalSpace() -> CGFloat { private func getTotalSpace() -> CGFloat {
guard let stackModel = stackModel else { return 0.0 } guard let stackModel = stackModel else { return 0.0 }
var totalSpace: CGFloat = 0.0 var totalSpace: CGFloat = 0.0
var firstMoleculeFound = false var firstMoleculeFound = false
@ -283,11 +317,13 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
totalSpace += (stackModel.useStackSpacingBeforeFirstItem ? spacing : stackItemModel.spacing ?? 0) totalSpace += (stackModel.useStackSpacingBeforeFirstItem ? spacing : stackItemModel.spacing ?? 0)
} }
} }
return totalSpace return totalSpace
} }
/// Adds the stack item view /// Adds the stack item view
private func addView(_ view: UIView,_ model: StackItemModelProtocol, totalSpacing: CGFloat, lastItem: Bool) { private func addView(_ view: UIView,_ model: StackItemModelProtocol, totalSpacing: CGFloat, lastItem: Bool) {
guard let stackModel = self.stackModel else { return } guard let stackModel = self.stackModel else { return }
guard !model.gone else { guard !model.gone else {
// Gone views do not show // Gone views do not show
@ -296,15 +332,15 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
} }
contentView.addSubview(view) contentView.addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false view.translatesAutoresizingMaskIntoConstraints = false
let spacing = model.spacing ?? stackModel.spacing let spacing = model.spacing ?? stackModel.spacing
if let container = view as? ContainerProtocol { if let container = view as? ContainerProtocol {
let verticalAlignment = (model as? ContainerModelProtocol)?.verticalAlignment ?? (container.view as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() ?? (model.percent == nil && stackModel.axis == .vertical ? .fill : (stackModel.axis == .vertical ? .leading : .center)) let verticalAlignment = (model as? ContainerModelProtocol)?.verticalAlignment ?? (container.view as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() ?? (model.percent == nil && stackModel.axis == .vertical ? .fill : (stackModel.axis == .vertical ? .leading : .center))
let horizontalAlignment = (model as? ContainerModelProtocol)?.horizontalAlignment ?? (container.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (stackModel.axis == .vertical || model.percent == nil ? .fill : .leading) let horizontalAlignment = (model as? ContainerModelProtocol)?.horizontalAlignment ?? (container.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (stackModel.axis == .vertical || model.percent == nil ? .fill : .leading)
container.alignHorizontal(horizontalAlignment) container.alignHorizontal(horizontalAlignment)
container.alignVertical(verticalAlignment) container.alignVertical(verticalAlignment)
} }
let first = contentView.subviews.count == 1 let first = contentView.subviews.count == 1
if stackModel.axis == .vertical { if stackModel.axis == .vertical {
if first { if first {
@ -344,6 +380,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
pinView(contentView, toView: view, attribute: .right, relation: .equal, priority: .required, constant: 0) pinView(contentView, toView: view, attribute: .right, relation: .equal, priority: .required, constant: 0)
} }
} }
stackItems.append(view) stackItems.append(view)
} }
} }

View File

@ -6,20 +6,28 @@
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import Foundation
@objcMembers public class StackModel: ContainerModel, StackModelProtocol, MoleculeModelProtocol { @objcMembers public class StackModel: ContainerModel, StackModelProtocol, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
static let defaultSpacing: CGFloat = 16.0 static let defaultSpacing: CGFloat = 16.0
public class var identifier: String { public class var identifier: String {
return "stack" return "stack"
} }
public var backgroundColor: Color? public var backgroundColor: Color?
public var molecules: [StackItemModelProtocol & MoleculeModelProtocol] public var molecules: [StackItemModelProtocol & MoleculeModelProtocol]
public var axis: NSLayoutConstraint.Axis = .vertical public var axis: NSLayoutConstraint.Axis = .vertical
public var spacing: CGFloat = StackModel.defaultSpacing public var spacing: CGFloat = StackModel.defaultSpacing
public var useStackSpacingBeforeFirstItem = false public var useStackSpacingBeforeFirstItem = false
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(molecules: [StackItemModelProtocol & MoleculeModelProtocol], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) { public init(molecules: [StackItemModelProtocol & MoleculeModelProtocol], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) {
self.molecules = molecules self.molecules = molecules
if let axis = axis { if let axis = axis {
@ -30,7 +38,11 @@ import Foundation
} }
super.init() super.init()
} }
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case moleculeName case moleculeName
case backgroundColor case backgroundColor
@ -38,7 +50,11 @@ import Foundation
case axis case axis
case spacing case spacing
} }
//--------------------------------------------------
// 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)
molecules = try typeContainer.decodeModels(codingKey: .molecules) molecules = try typeContainer.decodeModels(codingKey: .molecules)
@ -51,7 +67,7 @@ import Foundation
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
try super.init(from: decoder) try super.init(from: decoder)
} }
public override func encode(to encoder: Encoder) throws { public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder) try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)

View File

@ -108,6 +108,10 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
} }
} }
open override func accessibilityElementCount() -> Int {
return moleculesInfo?.count ?? 0
}
open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
guard let moleculeInfo = moleculesInfo?[indexPath.row], guard let moleculeInfo = moleculesInfo?[indexPath.row],
let estimatedHeight = (moleculeInfo.class as? MoleculeViewProtocol.Type)?.estimatedHeight(with: moleculeInfo.molecule, delegateObject() as? MVMCoreUIDelegateObject) let estimatedHeight = (moleculeInfo.class as? MoleculeViewProtocol.Type)?.estimatedHeight(with: moleculeInfo.molecule, delegateObject() as? MVMCoreUIDelegateObject)
@ -115,7 +119,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
return estimatedHeight return estimatedHeight
} }
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return moleculesInfo?.count ?? 0 return moleculesInfo?.count ?? 0
} }

View File

@ -8,10 +8,19 @@
import UIKit import UIKit
open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol { open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
var observer: NSKeyValueObservation? var observer: NSKeyValueObservation?
public var templateModel: StackPageTemplateModel? public var templateModel: StackPageTemplateModel?
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func handleNewData() { open override func handleNewData() {
topViewOutsideOfScroll = templateModel?.anchorHeader ?? false topViewOutsideOfScroll = templateModel?.anchorHeader ?? false
bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false
@ -20,9 +29,9 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
// For subclassing the model. // For subclassing the model.
open func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> StackPageTemplateModel { open func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> StackPageTemplateModel {
return try decoder.decode(StackPageTemplateModel.self, from: data) return try decoder.decode(StackPageTemplateModel.self, from: data)
} }
open override func parsePageJSON() throws { open override func parsePageJSON() throws {
try parseTemplate(json: loadObject?.pageJSON) try parseTemplate(json: loadObject?.pageJSON)
try super.parsePageJSON() try super.parsePageJSON()
@ -48,21 +57,23 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
open override func viewForTop() -> UIView? { open override func viewForTop() -> UIView? {
guard let headerModel = templateModel?.header, guard let headerModel = templateModel?.header,
let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar) else { let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar)
return nil else { return nil }
}
return molecule return molecule
} }
open override func viewForMiddle() -> UIView? { open override func viewForMiddle() -> UIView? {
guard let moleculeStackModel = templateModel?.moleculeStack else { return nil } guard let moleculeStackModel = templateModel?.moleculeStack else { return nil }
// By default: Stack template stack has vertical space before the first item, dynamic stack items have default horizontal padding. // By default: Stack template stack has vertical space before the first item, dynamic stack items have default horizontal padding.
let stack = MoleculeStackView(frame: .zero) let stack = MoleculeStackView(frame: .zero)
moleculeStackModel.useStackSpacingBeforeFirstItem = true moleculeStackModel.useStackSpacingBeforeFirstItem = true
for stackItem in moleculeStackModel.molecules { for stackItem in moleculeStackModel.molecules {
guard let stackItem = stackItem as? MoleculeStackItemModel, guard let stackItem = stackItem as? MoleculeStackItemModel,
stackItem.useHorizontalMargins == nil else { continue } stackItem.useHorizontalMargins == nil
else { continue }
stackItem.useHorizontalMargins = true stackItem.useHorizontalMargins = true
} }
stack.set(with: moleculeStackModel, delegateObject() as? MVMCoreUIDelegateObject, nil) stack.set(with: moleculeStackModel, delegateObject() as? MVMCoreUIDelegateObject, nil)
@ -71,14 +82,16 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
override open func viewForBottom() -> UIView? { override open func viewForBottom() -> UIView? {
guard let footerModel = templateModel?.footer, guard let footerModel = templateModel?.footer,
let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar) else { let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar)
return nil else { return nil }
}
return molecule return molecule
} }
// MARK: - cache handling //--------------------------------------------------
// MARK: - Cache Handling
//--------------------------------------------------
/// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map. /// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map.
open func updateRequiredModules() { open func updateRequiredModules() {
if let requiredModules = requiredModules(), let pageType = pageType { if let requiredModules = requiredModules(), let pageType = pageType {

View File

@ -95,14 +95,15 @@ public typealias ButtonAction = (Button) -> ()
self.model = model self.model = model
if let backgroundColor = model.backgroundColor { if let backgroundColor = model.backgroundColor {
self.backgroundColor = backgroundColor.uiColor self.backgroundColor = backgroundColor.uiColor
} }
if let model = model as? EnableableModelProtocol { if let model = model as? EnableableModelProtocol {
isEnabled = model.enabled isEnabled = model.enabled
} }
guard let model = model as? ButtonModelProtocol else { return } guard let model = model as? ButtonModelProtocol else { return }
set(with: model.action, delegateObject: delegateObject, additionalData: additionalData) set(with: model.action, delegateObject: delegateObject, additionalData: additionalData)
} }
@ -141,6 +142,8 @@ extension Button: MVMCoreViewProtocol {
/// Will be called only once. /// Will be called only once.
open func setupView() { open func setupView() {
isAccessibilityElement = true
accessibilityTraits = .button
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
insetsLayoutMarginsFromSafeArea = false insetsLayoutMarginsFromSafeArea = false
titleLabel?.numberOfLines = 0 titleLabel?.numberOfLines = 0

View File

@ -119,6 +119,7 @@ import UIKit
selectionStyle = .none selectionStyle = .none
insetsLayoutMarginsFromSafeArea = false insetsLayoutMarginsFromSafeArea = false
preservesSuperviewLayoutMargins = false preservesSuperviewLayoutMargins = false
isAccessibilityElement = false
contentView.insetsLayoutMarginsFromSafeArea = false contentView.insetsLayoutMarginsFromSafeArea = false
contentView.preservesSuperviewLayoutMargins = false contentView.preservesSuperviewLayoutMargins = false
styleStandard() styleStandard()
@ -192,7 +193,7 @@ import UIKit
caret.accessibilityTraits = .button caret.accessibilityTraits = .button
caret.size = .small(.vertical) caret.size = .small(.vertical)
if let size = caret.size?.dimensions() { if let size = caret.size?.dimensions() {
caret.frame = CGRect(origin: CGPoint.zero, size: size) caret.frame = CGRect(origin: .zero, size: size)
caretViewWidthSizeObject = MFSizeObject(standardSize: size.width, standardiPadPortraitSize: 9) caretViewWidthSizeObject = MFSizeObject(standardSize: size.width, standardiPadPortraitSize: 9)
caretViewHeightSizeObject = MFSizeObject(standardSize: size.height, standardiPadPortraitSize: 16) caretViewHeightSizeObject = MFSizeObject(standardSize: size.height, standardiPadPortraitSize: 16)
} }

View File

@ -9,6 +9,7 @@
import UIKit import UIKit
import MVMAnimationFramework import MVMAnimationFramework
open class ThreeLayerTableViewController: ProgrammaticTableViewController { open class ThreeLayerTableViewController: ProgrammaticTableViewController {
// The three main views // The three main views
private var topView: UIView? private var topView: UIView?
@ -40,7 +41,7 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController {
createViewForTableHeader() createViewForTableHeader()
createViewForTableFooter() createViewForTableFooter()
tableView?.reloadData() tableView?.reloadData()
accessibilityElements = [tableView as Any] // accessibilityElements = [tableView as Any]
} }
override open func viewDidLoad() { override open func viewDidLoad() {

View File

@ -506,8 +506,8 @@ import UIKit
// Needed otherwise when subclassed, the extension gets called. // Needed otherwise when subclassed, the extension gets called.
open func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) {} open func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) {}
open func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil } open func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil }
open func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) {} open func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) { }
open func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) {} open func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - MVMCoreUIDetailViewProtocol // MARK: - MVMCoreUIDetailViewProtocol

View File

@ -8,7 +8,11 @@
import UIKit import UIKit
open class Container: View, ContainerProtocol { open class Container: View, ContainerProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var view: UIView? public var view: UIView?
let containerHelper = ContainerHelper() let containerHelper = ContainerHelper()
@ -17,10 +21,15 @@ open class Container: View, ContainerProtocol {
get { return model as? ContainerModelProtocol } get { return model as? ContainerModelProtocol }
} }
// MARK:- MoleculeViewProtocol //--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData) super.set(with: model, delegateObject, additionalData)
guard let containerModel = model as? ContainerModelProtocol else { return } guard let containerModel = model as? ContainerModelProtocol else { return }
containerHelper.set(with: containerModel, for: view as? MVMCoreUIViewConstrainingProtocol) containerHelper.set(with: containerModel, for: view as? MVMCoreUIViewConstrainingProtocol)
} }
@ -29,7 +38,10 @@ open class Container: View, ContainerProtocol {
(view as? MoleculeViewProtocol)?.reset() (view as? MoleculeViewProtocol)?.reset()
} }
// MARK:- ContainerProtocol //--------------------------------------------------
// MARK: - ContainerProtocol
//--------------------------------------------------
open func alignHorizontal(_ alignment: UIStackView.Alignment) { open func alignHorizontal(_ alignment: UIStackView.Alignment) {
containerHelper.alignHorizontal(alignment) containerHelper.alignHorizontal(alignment)
} }
@ -45,12 +57,13 @@ open class Container: View, ContainerProtocol {
// MARK: - MVMCoreViewProtocol // MARK: - MVMCoreViewProtocol
public extension Container { public extension Container {
override func updateView(_ size: CGFloat) { override func updateView(_ size: CGFloat) {
super.updateView(size) super.updateView(size)
(view as? MVMCoreViewProtocol)?.updateView(size) (view as? MVMCoreViewProtocol)?.updateView(size)
containerHelper.updateViewMargins(self, model: containerModel, size: size) containerHelper.updateViewMargins(self, model: containerModel, size: size)
} }
/// Will be called only once. /// Will be called only once.
override func setupView() { override func setupView() {
super.setupView() super.setupView()