From 5b83adf751b4bb29dc4eca984e764bed62b6280f Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Fri, 16 Jun 2023 14:04:42 -0400 Subject: [PATCH] Accessibility Traits Coddle --- .../Atomic/Atoms/Views/Label/Label.swift | 3 + .../Atomic/Atoms/Views/Label/LabelModel.swift | 4 + .../UIAccessibilityTraits+Codable.swift | 125 ++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 MVMCoreUI/Atomic/Extensions/UIAccessibilityTraits+Codable.swift diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index 62dab9c2..01614f31 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -276,6 +276,9 @@ public typealias ActionBlock = () -> () guard let labelModel = model as? LabelModel else { return } text = labelModel.text + if let accessibilityTraits = labelModel.accessibilityTraits { + self.accessibilityTraits = accessibilityTraits + } resetAttributeStyle() diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift index d1995d19..70f1cc62 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift @@ -28,6 +28,7 @@ public var makeWholeViewClickable: Bool? public var numberOfLines: Int? public var shouldMaskRecordedView: Bool? = false + public var accessibilityTraits: UIAccessibilityTraits? //-------------------------------------------------- // MARK: - Keys @@ -50,6 +51,7 @@ case makeWholeViewClickable case numberOfLines case shouldMaskRecordedView + case accessibilityTraits } enum AttributeTypeKey: String, CodingKey { @@ -96,6 +98,7 @@ makeWholeViewClickable = try typeContainer.decodeIfPresent(Bool.self, forKey: .makeWholeViewClickable) numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines) shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? false + accessibilityTraits = try typeContainer.decodeIfPresent(UIAccessibilityTraits.self, forKey: .accessibilityTraits) // Later make protocol based validate outside of decoding? if let attributes = attributes { @@ -121,5 +124,6 @@ try container.encodeIfPresent(makeWholeViewClickable, forKey: .makeWholeViewClickable) try container.encodeIfPresent(numberOfLines, forKey: .numberOfLines) try container.encodeIfPresent(shouldMaskRecordedView, forKey: .shouldMaskRecordedView) + try container.encodeIfPresent(accessibilityTraits, forKey: .accessibilityTraits) } } diff --git a/MVMCoreUI/Atomic/Extensions/UIAccessibilityTraits+Codable.swift b/MVMCoreUI/Atomic/Extensions/UIAccessibilityTraits+Codable.swift new file mode 100644 index 00000000..4eb1ea2a --- /dev/null +++ b/MVMCoreUI/Atomic/Extensions/UIAccessibilityTraits+Codable.swift @@ -0,0 +1,125 @@ +// +// UIAccessibilityTraits+Codable.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 6/16/23. +// Copyright © 2023 Verizon Wireless. All rights reserved. +// + +import Foundation + +extension UIAccessibilityTraits: Codable { + private static func trait(from string: String) throws -> UIAccessibilityTraits { + switch string { + case "none": + return .none + case "button": + return .button + case "link": + return .link + case "image": + return .image + case "searchField": + return .searchField + case "keyboardKey": + return .keyboardKey + case "staticText": + return .staticText + case "header": + return .header + case "tabBar": + return .tabBar + case "summaryElement": + return .summaryElement + case "selected": + return .selected + case "notEnabled": + return .notEnabled + case "adjustable": + return .adjustable + case "allowsDirectInteraction": + return .allowsDirectInteraction + case "updatesFrequently": + return .updatesFrequently + case "causesPageTurn": + return .causesPageTurn + case "playsSound": + return .playsSound + case "startsMediaSession": + return .startsMediaSession + default: + throw ModelRegistry.Error.decoderOther(message: "Unsupported accessibility trait: \(string)") + } + } + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + + // Iterate and decode each. + var accessibilityTrait: UIAccessibilityTraits = [] + while !container.isAtEnd { + let traitString = try container.decode(String.self) + let trait = try UIAccessibilityTraits.trait(from: traitString) + accessibilityTrait.insert(trait) + } + self = accessibilityTrait + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + if self.contains(.none) { + try container.encode("none") + } + if self.contains(.button) { + try container.encode("button") + } + if self.contains(.link) { + try container.encode("link") + } + if self.contains(.image) { + try container.encode("image") + } + if self.contains(.searchField) { + try container.encode("searchField") + } + if self.contains(.keyboardKey) { + try container.encode("keyboardKey") + } + if self.contains(.staticText) { + try container.encode("staticText") + } + if self.contains(.header) { + try container.encode("header") + } + if self.contains(.tabBar) { + try container.encode("tabBar") + } + if self.contains(.summaryElement) { + try container.encode("summaryElement") + } + if self.contains(.selected) { + try container.encode("selected") + } + if self.contains(.notEnabled) { + try container.encode("notEnabled") + } + if self.contains(.adjustable) { + try container.encode("adjustable") + } + if self.contains(.allowsDirectInteraction) { + try container.encode("allowsDirectInteraction") + } + if self.contains(.updatesFrequently) { + try container.encode("updatesFrequently") + } + if self.contains(.causesPageTurn) { + try container.encode("causesPageTurn") + } + if self.contains(.playsSound) { + try container.encode("playsSound") + } + if self.contains(.startsMediaSession) { + try container.encode("startsMediaSession") + } + } +}