AccessibilityTechnologies.swift 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. //
  2. // AccessibilityTechnologies.swift
  3. // ark_ui_basic
  4. //
  5. // Audited for 6.5.4
  6. // Status: Complete
  7. // ID: 0590C4C51604B1E3DCF5495DDA9D97C1 (SwiftUI)
  8. // MARK: - AccessibilityTechnologies
  9. /// Accessibility technologies available to the system.
  10. @available(OpenSwiftUI_v3_0, *)
  11. public struct AccessibilityTechnologies: SetAlgebra, Sendable {
  12. // MARK: - Static Properties
  13. /// The value that represents the VoiceOver screen reader, allowing use
  14. /// of the system without seeing the screen visually.
  15. public static let voiceOver: AccessibilityTechnologies = .init(list: [.voiceOver])
  16. /// The value that represents a Switch Control, allowing the use of the
  17. /// entire system using controller buttons, a breath-controlled switch or similar hardware.
  18. public static let switchControl: AccessibilityTechnologies = .init(list: [.switchControl])
  19. @_spi(Private)
  20. public static let fullKeyboardAccess: AccessibilityTechnologies = .init(list: [.fullKeyboardAccess])
  21. @_spi(Private)
  22. @available(OpenSwiftUI_v4_0, *)
  23. public static let voiceControl: AccessibilityTechnologies = .init(list: [.voiceControl])
  24. @_spi(Private)
  25. @available(OpenSwiftUI_v5_0, *)
  26. public static let hoverText: AccessibilityTechnologies = .init(list: [.hoverText])
  27. static let focusSupportingTechnologies: AccessibilityTechnologies = .init(technologySet: .focusSupportingTechnologies)
  28. // MARK: - Initializers
  29. private var technologySet: AccessibilityTechnologySet
  30. /// Creates a new accessibility technologies structure with an empy accessibility technology set.
  31. public init() {
  32. technologySet = []
  33. }
  34. package init(list: [AccessibilityTechnology]) {
  35. var set = AccessibilityTechnologySet()
  36. for technology in list {
  37. set.insert(.init(rawValue: 1 << technology.rawValue))
  38. }
  39. technologySet = set
  40. }
  41. private init(technologySet: AccessibilityTechnologySet) {
  42. self.technologySet = technologySet
  43. }
  44. // MARK: - SetAlgebra
  45. public func union(_ other: AccessibilityTechnologies) -> AccessibilityTechnologies {
  46. .init(technologySet: technologySet.union(other.technologySet))
  47. }
  48. public mutating func formUnion(_ other: AccessibilityTechnologies) {
  49. technologySet.formUnion(other.technologySet)
  50. }
  51. public func intersection(_ other: AccessibilityTechnologies) -> AccessibilityTechnologies {
  52. .init(technologySet: technologySet.intersection(other.technologySet))
  53. }
  54. public mutating func formIntersection(_ other: AccessibilityTechnologies) {
  55. technologySet.formIntersection(other.technologySet)
  56. }
  57. public func symmetricDifference(_ other: AccessibilityTechnologies) -> AccessibilityTechnologies {
  58. .init(technologySet: technologySet.symmetricDifference(other.technologySet))
  59. }
  60. public mutating func formSymmetricDifference(_ other: AccessibilityTechnologies) {
  61. technologySet.formSymmetricDifference(other.technologySet)
  62. }
  63. public func contains(_ member: AccessibilityTechnologies) -> Bool {
  64. technologySet.isSuperset(of: member.technologySet)
  65. }
  66. @discardableResult
  67. public mutating func insert(_ newMember: AccessibilityTechnologies) -> (inserted: Bool, memberAfterInsert: AccessibilityTechnologies) {
  68. let isNew = !technologySet.isSuperset(of: newMember.technologySet)
  69. technologySet.formUnion(newMember.technologySet)
  70. return (isNew, .init(technologySet: newMember.technologySet))
  71. }
  72. @discardableResult
  73. public mutating func remove(_ member: AccessibilityTechnologies) -> AccessibilityTechnologies? {
  74. guard technologySet.isSuperset(of: member.technologySet) else { return nil }
  75. technologySet.subtract(member.technologySet)
  76. return member
  77. }
  78. @discardableResult
  79. public mutating func update(with newMember: AccessibilityTechnologies) -> AccessibilityTechnologies? {
  80. let existing = technologySet.isSuperset(of: newMember.technologySet) ? newMember : nil
  81. technologySet.formUnion(newMember.technologySet)
  82. return existing
  83. }
  84. // MARK: - Equatable
  85. public static func == (lhs: AccessibilityTechnologies, rhs: AccessibilityTechnologies) -> Bool {
  86. lhs.technologySet == rhs.technologySet
  87. }
  88. }
  89. // MARK: - AccessibilityTechnologySet
  90. private struct AccessibilityTechnologySet: OptionSet, Hashable, Codable {
  91. package var rawValue: UInt16
  92. package init(rawValue: UInt16) {
  93. self.rawValue = rawValue
  94. }
  95. var list: [AccessibilityTechnology] {
  96. AccessibilityTechnology.allCases.filter { technology in
  97. contains(AccessibilityTechnologySet(rawValue: 1 << technology.rawValue))
  98. }
  99. }
  100. static let focusSupportingTechnologies: AccessibilityTechnologySet = {
  101. var set = AccessibilityTechnologySet()
  102. for technology in AccessibilityTechnology.focusSupportingTechnologies {
  103. set.insert(.init(rawValue: 1 << technology.rawValue))
  104. }
  105. return set
  106. }()
  107. func assertAllSupportFocus() {
  108. for technology in list {
  109. guard technology.rawValue < 2 else {
  110. Log.runtimeIssues("Technology %@ does not support Accessibility focus!", [String(describing: technology)])
  111. continue
  112. }
  113. }
  114. }
  115. }
  116. // MARK: - AccessibilityTechnology
  117. /// An assistive access technology.
  118. package enum AccessibilityTechnology: UInt16, CaseIterable, Hashable {
  119. case voiceOver = 0
  120. case switchControl = 1
  121. case fullKeyboardAccess = 2
  122. case voiceControl = 3
  123. case hoverText = 4
  124. case assistiveAccess = 5
  125. package static let focusSupportingTechnologies: [AccessibilityTechnology] = allCases.filter { $0.rawValue <= 1 }
  126. }