diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift index 796bf617..1cf80fc3 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -79,8 +79,6 @@ import UIKit heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1) heightConstraint?.isActive = true isAccessibilityElement = true - accessibilityTraits = .button - updateAccessibilityLabel() } public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { @@ -89,6 +87,8 @@ import UIKit self.additionalData = additionalData guard let model = model as? HeartModel else { return } isSelected = model.isActive + isEnabled = model.enabled + updateAccessibilityLabel() } //-------------------------------------------------- @@ -96,11 +96,13 @@ import UIKit //-------------------------------------------------- /// Adjust accessibility label based on selection of Heart. func updateAccessibilityLabel() { - accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint") + accessibilityHint = isEnabled ? MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint") : nil + accessibilityTraits = isEnabled ? .button : .none accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_selected_state" : "heart_not_selected_state") } func tapAction() { + guard isEnabled else { return } isSelected = !isSelected if let heartModel = heartModel { Button.performButtonAction(with: heartModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: heartModel) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift index 8001ddd5..7411899c 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift @@ -8,7 +8,7 @@ import Foundation -open class HeartModel: MoleculeModelProtocol { +open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol { //-------------------------------------------------- // MARK: - Properties @@ -19,6 +19,7 @@ open class HeartModel: MoleculeModelProtocol { public var activeColor: Color = Color(uiColor: .mvmRed) public var inActiveColor: Color = Color(uiColor: .clear) public var action: ActionModelProtocol = ActionNoopModel() + public var enabled: Bool = true //-------------------------------------------------- // MARK: - Keys @@ -30,6 +31,7 @@ open class HeartModel: MoleculeModelProtocol { case activeColor case inActiveColor case action + case enabled } //-------------------------------------------------- @@ -51,6 +53,9 @@ open class HeartModel: MoleculeModelProtocol { if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) { self.action = action } + if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { + self.enabled = enabled + } } public func encode(to encoder: Encoder) throws { @@ -61,5 +66,6 @@ open class HeartModel: MoleculeModelProtocol { try container.encode(activeColor, forKey: .activeColor) try container.encode(inActiveColor, forKey: .inActiveColor) try container.encodeModel(action, forKey: .action) + try container.encode(enabled, forKey: .enabled) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStoreLocator.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStoreLocator.swift index 6a1f0dc5..d81ab5c8 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStoreLocator.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStoreLocator.swift @@ -42,8 +42,6 @@ addMolecule(stack) stack.restack() horizontalStack.restack() - accessibilityHint = heart.accessibilityHint - accessibilityTraits = heart.accessibilityTraits } public override func updateView(_ size: CGFloat) { @@ -123,20 +121,40 @@ } func updateAccessibilityLabel() { - if let accessoryView = accessoryView { - // Both caret and heart. + let hasHeart = !(horizontalStack.stackModel?.molecules[1].gone ?? true) + if let accessoryView = accessoryView, + hasHeart { + // Both accessory and heart actions. isAccessibilityElement = false accessoryView.accessibilityLabel = getAccessibilityMessage() accessibilityElements = [accessoryView, heart] } else { // Make whole cell focusable if no action. isAccessibilityElement = true - if let message = getAccessibilityMessage(), - let heartLabel = heart.accessibilityLabel { - accessibilityLabel = message + ", " + heartLabel + var message = getAccessibilityMessage() + if hasHeart { + accessibilityHint = heart.accessibilityHint + if let heartLabel = heart.accessibilityLabel { + message = (message ?? "") + ", " + heartLabel + } } else { - accessibilityLabel = getAccessibilityMessage() + accessibilityHint = nil } + accessibilityLabel = message } } + + // Ensures voice over does not read "selected" after user triggers action on cell. + override public var accessibilityTraits: UIAccessibilityTraits { + get { + if (accessoryView != nil) { + return .button + } else if (!(horizontalStack.stackModel?.molecules[1].gone ?? true)) { + return heart.accessibilityTraits + } else { + return .none + } + } + set {} + } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStoreLocatorModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStoreLocatorModel.swift index 32392b50..10a0cd29 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStoreLocatorModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Miscellaneous/ListStoreLocatorModel.swift @@ -12,7 +12,7 @@ public class ListStoreLocatorModel: ListItemModel, MoleculeModelProtocol { //-------------------------------------------------- public static var identifier = "listStoreLocator" - public var heart: HeartModel + public var heart: HeartModel? public var leftHeadline: LabelModel public var leftBody: LabelModel public var leftSubBody: LabelModel @@ -22,7 +22,7 @@ public class ListStoreLocatorModel: ListItemModel, MoleculeModelProtocol { // MARK: - Initializer //-------------------------------------------------- - public init(heart: HeartModel, leftHeadline: LabelModel, leftBody: LabelModel, leftSubBody: LabelModel, rightLabel: LabelModel) { + public init(heart: HeartModel?, leftHeadline: LabelModel, leftBody: LabelModel, leftSubBody: LabelModel, rightLabel: LabelModel) { self.heart = heart self.leftHeadline = leftHeadline self.leftBody = leftBody @@ -59,7 +59,7 @@ public class ListStoreLocatorModel: ListItemModel, MoleculeModelProtocol { public required init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - heart = try typeContainer.decode(HeartModel.self, forKey:.heart) + heart = try typeContainer.decodeIfPresent(HeartModel.self, forKey:.heart) leftHeadline = try typeContainer.decode(LabelModel.self, forKey: .leftHeadline) leftBody = try typeContainer.decode(LabelModel.self, forKey: .leftBody) leftSubBody = try typeContainer.decode(LabelModel.self, forKey: .leftSubBody) @@ -71,7 +71,7 @@ public class ListStoreLocatorModel: ListItemModel, MoleculeModelProtocol { try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) - try container.encode(heart, forKey: .heart) + try container.encodeIfPresent(heart, forKey: .heart) try container.encode(leftHeadline, forKey: .leftHeadline) try container.encode(leftBody, forKey: .leftBody) try container.encode(leftSubBody, forKey: .leftSubBody)