AccessibilityQuickAction.swift 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. //
  2. // AccessibilityQuickAction.swift
  3. // ark_ui_basic
  4. //
  5. // Audited for 6.5.4
  6. // Status: TODO
  7. // ID: B8D2E4520F2964BB14185EE65411F685 (SwiftUI)
  8. #if OPENSWIFTUI_OPENCOMBINE
  9. import OpenCombine
  10. #else
  11. import Combine
  12. #endif
  13. import ark_ui_basic_core
  14. // MARK: - AccessibilityQuickActionProxy [TODO]
  15. private class AccessibilityQuickActionProxy {
  16. @Published var state: AccessibilityQuickActionState = .inactive
  17. var label: String?
  18. var isActive: Binding<Bool>?
  19. var action: (() -> Void)?
  20. var isEnabled: Bool = true
  21. let style: _AccessibilityQuickActionStyle.RawValue
  22. init(style: _AccessibilityQuickActionStyle.RawValue) {
  23. self.style = style
  24. }
  25. }
  26. // MARK: - _AccessibilityQuickActionStyle
  27. @available(OpenSwiftUI_v4_0, *)
  28. public struct _AccessibilityQuickActionStyle {
  29. enum RawValue: Equatable {
  30. case prompt
  31. case outline
  32. }
  33. let rawValue: RawValue
  34. }
  35. @available(*, unavailable)
  36. extension _AccessibilityQuickActionStyle: Sendable {}
  37. // MARK: - AccessibilityQuickActionStyle
  38. /// A type that describes the presentation style of an
  39. /// accessibility quick action.
  40. @available(OpenSwiftUI_v4_0, *)
  41. @available(iOS, unavailable)
  42. @available(macOS, unavailable)
  43. @available(tvOS, unavailable)
  44. @available(visionOS, unavailable)
  45. public protocol AccessibilityQuickActionStyle {
  46. var _style: _AccessibilityQuickActionStyle { get }
  47. }
  48. // MARK: - AccessibilityQuickActionPromptStyle
  49. /// A presentation style that displays a prompt to the user when
  50. /// the accessibility quick action is active.
  51. ///
  52. /// Don't use this type directly. Instead, use ``AccessibilityQuickActionStyle/prompt``.
  53. @available(OpenSwiftUI_v4_0, *)
  54. @available(iOS, unavailable)
  55. @available(macOS, unavailable)
  56. @available(tvOS, unavailable)
  57. @available(visionOS, unavailable)
  58. public struct AccessibilityQuickActionPromptStyle: AccessibilityQuickActionStyle {
  59. public var _style: _AccessibilityQuickActionStyle {
  60. .init(rawValue: .prompt)
  61. }
  62. @usableFromInline
  63. init() {}
  64. }
  65. @available(*, unavailable)
  66. extension AccessibilityQuickActionPromptStyle: Sendable {}
  67. @available(OpenSwiftUI_v4_0, *)
  68. @available(iOS, unavailable)
  69. @available(macOS, unavailable)
  70. @available(tvOS, unavailable)
  71. @available(visionOS, unavailable)
  72. extension AccessibilityQuickActionStyle where Self == AccessibilityQuickActionPromptStyle {
  73. @_alwaysEmitIntoClient
  74. public static var prompt: AccessibilityQuickActionPromptStyle {
  75. AccessibilityQuickActionPromptStyle()
  76. }
  77. }
  78. // MARK: - AccessibilityQuickActionOutlineStyle
  79. /// A presentation style that displays a prompt to the user when
  80. /// the accessibility quick action is active.
  81. ///
  82. /// Don't use this type directly. Instead, use ``AccessibilityQuickActionStyle/outline``.
  83. @available(OpenSwiftUI_v4_0, *)
  84. @available(iOS, unavailable)
  85. @available(macOS, unavailable)
  86. @available(tvOS, unavailable)
  87. @available(visionOS, unavailable)
  88. public struct AccessibilityQuickActionOutlineStyle: AccessibilityQuickActionStyle {
  89. public var _style: _AccessibilityQuickActionStyle {
  90. .init(rawValue: .outline)
  91. }
  92. @usableFromInline
  93. init() {}
  94. }
  95. @available(OpenSwiftUI_v4_0, *)
  96. @available(iOS, unavailable)
  97. @available(macOS, unavailable)
  98. @available(tvOS, unavailable)
  99. @available(visionOS, unavailable)
  100. extension AccessibilityQuickActionStyle where Self == AccessibilityQuickActionOutlineStyle {
  101. @_alwaysEmitIntoClient
  102. public static var outline: AccessibilityQuickActionOutlineStyle {
  103. AccessibilityQuickActionOutlineStyle()
  104. }
  105. }
  106. // MARK: - AccessibilityQuickActionState
  107. enum AccessibilityQuickActionState {
  108. case inactive
  109. case willHint
  110. case willPulse
  111. case willActivate
  112. }
  113. // MARK: - AccessibilityQuickActionsKey
  114. private struct AccessibilityQuickActionsKey: EnvironmentKey {
  115. static var defaultValue: Bool { false }
  116. }
  117. // MARK: - EnvironmentValues + AccessibilityQuickActions
  118. extension EnvironmentValues {
  119. /// A Boolean that indicates whether the quick actions feature is enabled.
  120. ///
  121. /// The system uses quick actions to provide users with a
  122. /// fast alternative interaction method. Quick actions can be
  123. /// presented to users with a textual banner at the top of their
  124. /// screen and/or an outline around a view that is already on screen.
  125. @available(OpenSwiftUI_v4_0, *)
  126. public var accessibilityQuickActionsEnabled: Bool {
  127. self[AccessibilityQuickActionsKey.self]
  128. }
  129. @available(OpenSwiftUI_v4_0, *)
  130. public var _accessibilityQuickActionsEnabled: Bool {
  131. get { self[AccessibilityQuickActionsKey.self] }
  132. set { self[AccessibilityQuickActionsKey.self] = newValue }
  133. }
  134. }
  135. // MARK: - View + AccessibilityQuickAction
  136. @available(OpenSwiftUI_v4_0, *)
  137. @available(iOS, unavailable)
  138. @available(macOS, unavailable)
  139. @available(tvOS, unavailable)
  140. @available(visionOS, unavailable)
  141. extension View {
  142. /// Adds a quick action to be shown by the system when active.
  143. ///
  144. /// The quick action will automatically become active when the
  145. /// view appears. If the view is disabled, the action will defer
  146. /// becoming active until the view is no longer disabled.
  147. ///
  148. /// The following example shows how to add a quick action to
  149. /// pause and resume a workout, with the ``AccessibilityQuickActionStyle/prompt`` style.
  150. ///
  151. /// @State private var isPaused = false
  152. ///
  153. /// var body: some View {
  154. /// WorkoutView(isPaused: $isPaused)
  155. /// .accessibilityQuickAction(style: .prompt) {
  156. /// Button(isPaused ? "Resume" : "Pause") {
  157. /// isPaused.toggle()
  158. /// }
  159. /// }
  160. /// }
  161. ///
  162. /// The following example shows how to add a quick action to
  163. /// play and pause music, with the ``AccessibilityQuickActionStyle/outline`` style.
  164. ///
  165. /// @State private var isPlaying = false
  166. ///
  167. /// var body: some View {
  168. /// PlayButton(isPlaying: $isPlaying)
  169. /// .contentShape(.focusEffect, Circle())
  170. /// .accessibilityQuickAction(style: .outline) {
  171. /// Button(isPlaying ? "Pause" : "Play") {
  172. /// isPlaying.toggle()
  173. /// }
  174. /// }
  175. /// }
  176. ///
  177. public func accessibilityQuickAction<Style: AccessibilityQuickActionStyle, Content: View>(
  178. style: Style,
  179. @ViewBuilder content: @escaping () -> Content
  180. ) -> some View {
  181. modifier(
  182. AccessibilityQuickActionModifier(
  183. content: content(),
  184. style: style._style.rawValue
  185. )
  186. )
  187. }
  188. /// Adds a quick action to be shown by the system when active.
  189. ///
  190. /// The following example shows how to add a quick action to
  191. /// pause and resume a workout, with the ``AccessibilityQuickActionStyle/prompt`` style.
  192. ///
  193. /// @State private var isPaused = false
  194. /// @State private var isQuickActionActive = false
  195. ///
  196. /// var body: some View {
  197. /// WorkoutView(isPaused: $isPaused)
  198. /// .accessibilityQuickAction(style: .prompt, isActive: $isQuickActionActive) {
  199. /// Button(isPaused ? "Resume" : "Pause") {
  200. /// isPaused.toggle()
  201. /// }
  202. /// }
  203. /// }
  204. ///
  205. /// The following example shows how to add a quick action to
  206. /// play and pause music, with the ``AccessibilityQuickActionStyle/outline`` style.
  207. ///
  208. /// @State private var isPlaying = false
  209. /// @State private var isQuickActionActive = false
  210. ///
  211. /// var body: some View {
  212. /// PlayButton(isPlaying: $isPlaying)
  213. /// .contentShape(.focusEffect, Circle())
  214. /// .accessibilityQuickAction(style: .outline, isActive: $isQuickActionActive) {
  215. /// Button(isPlaying ? "Pause" : "Play") {
  216. /// isPlaying.toggle()
  217. /// }
  218. /// }
  219. /// }
  220. ///
  221. public func accessibilityQuickAction<Style: AccessibilityQuickActionStyle, Content: View>(
  222. style: Style,
  223. isActive: Binding<Bool>,
  224. @ViewBuilder content: @escaping () -> Content
  225. ) -> some View {
  226. modifier(
  227. AccessibilityQuickActionModifier(
  228. content: content(),
  229. isActive: isActive,
  230. style: style._style.rawValue
  231. )
  232. )
  233. }
  234. }
  235. // MARK: - AccessibilityQuickActionModifier [WIP]
  236. private struct AccessibilityQuickActionModifier<Content>: MultiViewModifier, PrimitiveViewModifier where Content: View {
  237. var content: Content
  238. var isActive: Binding<Bool>?
  239. var style: _AccessibilityQuickActionStyle.RawValue
  240. nonisolated static func _makeView(
  241. modifier: _GraphValue<Self>,
  242. inputs: _ViewInputs,
  243. body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
  244. ) -> _ViewOutputs {
  245. _openSwiftUIPlatformUnimplementedFailure()
  246. }
  247. }