@swiftbrowser/swift 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (393) hide show
  1. package/Package.swift +200 -9
  2. package/README.md +7 -9
  3. package/Sources/AVFoundation/AVFoundation.swift +131 -0
  4. package/Sources/AVFoundation/Asset.swift +487 -0
  5. package/Sources/AVFoundation/AudioSession.swift +144 -0
  6. package/Sources/AVFoundation/CMTime.swift +303 -0
  7. package/Sources/AVFoundation/Capture.swift +688 -0
  8. package/Sources/AVFoundation/Player.swift +749 -0
  9. package/Sources/AVFoundation/PlayerView.swift +117 -0
  10. package/Sources/AVKit/AVKit.swift +132 -0
  11. package/Sources/Accelerate/Accelerate.swift +122 -0
  12. package/Sources/AppIntents/AppIntents.swift +144 -0
  13. package/Sources/AppIntents/Parameters.swift +220 -0
  14. package/Sources/AppIntents/Shortcuts.swift +159 -0
  15. package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
  16. package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
  17. package/Sources/AuthenticationServices/Authorization.swift +251 -0
  18. package/Sources/Charts/Charts.swift +0 -4
  19. package/Sources/Combine/AnyCancellable.swift +65 -0
  20. package/Sources/Combine/AnyPublisher.swift +148 -0
  21. package/Sources/Combine/AnySubscriber.swift +230 -0
  22. package/Sources/Combine/Cancellable.swift +35 -0
  23. package/Sources/Combine/Codable.swift +29 -0
  24. package/Sources/Combine/CombineIdentifier.swift +45 -0
  25. package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
  26. package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
  27. package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
  28. package/Sources/Combine/CurrentValueSubject.swift +252 -0
  29. package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
  30. package/Sources/Combine/Future.swift +228 -0
  31. package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
  32. package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
  33. package/Sources/Combine/Helpers/ConduitList.swift +59 -0
  34. package/Sources/Combine/Helpers/DebugHook.swift +177 -0
  35. package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
  36. package/Sources/Combine/Helpers/Locking.swift +30 -0
  37. package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
  38. package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
  39. package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
  40. package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
  41. package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
  42. package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
  43. package/Sources/Combine/Helpers/Utils.swift +30 -0
  44. package/Sources/Combine/Helpers/Violations.swift +33 -0
  45. package/Sources/Combine/ImmediateScheduler.swift +178 -0
  46. package/Sources/Combine/LICENSE +21 -0
  47. package/Sources/Combine/NotificationPublisher.swift +48 -0
  48. package/Sources/Combine/ObjectWillChange.swift +46 -0
  49. package/Sources/Combine/PassthroughSubject.swift +222 -0
  50. package/Sources/Combine/Publisher+Subscribe.swift +53 -0
  51. package/Sources/Combine/Publishers/Deferred.swift +48 -0
  52. package/Sources/Combine/Publishers/Empty.swift +54 -0
  53. package/Sources/Combine/Publishers/Fail.swift +42 -0
  54. package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
  55. package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
  56. package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
  57. package/Sources/Combine/Publishers/Just.swift +313 -0
  58. package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
  59. package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
  60. package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
  61. package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
  62. package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
  63. package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
  64. package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
  65. package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
  66. package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
  67. package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
  68. package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
  69. package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
  70. package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
  71. package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
  72. package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
  73. package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
  74. package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
  75. package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
  76. package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
  77. package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
  78. package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
  79. package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
  80. package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
  81. package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
  82. package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
  83. package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
  84. package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
  85. package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
  86. package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
  87. package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
  88. package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
  89. package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
  90. package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
  91. package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
  92. package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
  93. package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
  94. package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
  95. package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
  96. package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
  97. package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
  98. package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
  99. package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
  100. package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
  101. package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
  102. package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
  103. package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
  104. package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
  105. package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
  106. package/Sources/Combine/Publishers/Publishers.swift +13 -0
  107. package/Sources/Combine/Publishers/Record.swift +237 -0
  108. package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
  109. package/Sources/Combine/Result.swift +46 -0
  110. package/Sources/Combine/Scheduler.swift +89 -0
  111. package/Sources/Combine/Schedulers.swift +211 -0
  112. package/Sources/Combine/Subject+Void.swift +17 -0
  113. package/Sources/Combine/Subscriber+Void.swift +20 -0
  114. package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
  115. package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
  116. package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
  117. package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
  118. package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
  119. package/Sources/Combine/Subscription.swift +22 -0
  120. package/Sources/Combine/Subscriptions.swift +42 -0
  121. package/Sources/Combine/SwiftUIObservation.swift +10 -0
  122. package/Sources/Combine/_Introspection.swift +107 -0
  123. package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
  124. package/Sources/Compression/Compression.swift +365 -0
  125. package/Sources/Compression/Deflate.swift +407 -0
  126. package/Sources/Compression/Zlib.swift +179 -0
  127. package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
  128. package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
  129. package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
  130. package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
  131. package/Sources/CoreImage/CIColor.swift +41 -0
  132. package/Sources/CoreImage/CIContext.swift +31 -0
  133. package/Sources/CoreImage/CIDetector.swift +57 -0
  134. package/Sources/CoreImage/CIFilter.swift +243 -0
  135. package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
  136. package/Sources/CoreImage/CIImage.swift +162 -0
  137. package/Sources/CoreImage/QRCode.swift +393 -0
  138. package/Sources/CoreLocation/Coordinate.swift +30 -0
  139. package/Sources/CoreLocation/Location.swift +65 -0
  140. package/Sources/CoreML/Evaluation.swift +414 -0
  141. package/Sources/CoreML/FeatureValue.swift +266 -0
  142. package/Sources/CoreML/Model.swift +269 -0
  143. package/Sources/CoreML/MultiArray.swift +92 -0
  144. package/Sources/CoreML/Specification.swift +233 -0
  145. package/Sources/CoreText/CoreText.swift +64 -0
  146. package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
  147. package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
  148. package/Sources/CryptoKit/CryptoKit.swift +375 -0
  149. package/Sources/CryptoKit/Curve25519.swift +317 -0
  150. package/Sources/CryptoKit/P256.swift +321 -0
  151. package/Sources/FoundationBridge/AppStorage.swift +165 -0
  152. package/Sources/FoundationBridge/AssetResources.swift +90 -0
  153. package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
  154. package/Sources/FoundationBridge/AsyncImage.swift +116 -0
  155. package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
  156. package/Sources/{_FoundationCommon → FoundationBridge}/Bundle.swift +41 -4
  157. package/Sources/FoundationBridge/CombineExports.swift +8 -0
  158. package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
  159. package/Sources/FoundationBridge/Dispatch.swift +458 -0
  160. package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
  161. package/Sources/FoundationBridge/FileImporter.swift +128 -0
  162. package/Sources/FoundationBridge/FileSystem.swift +68 -0
  163. package/Sources/FoundationBridge/FoundationBridge.swift +24 -72
  164. package/Sources/FoundationBridge/HostResolution.swift +31 -0
  165. package/Sources/FoundationBridge/ItemProvider.swift +655 -0
  166. package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
  167. package/Sources/FoundationBridge/Links.swift +127 -0
  168. package/Sources/FoundationBridge/ListFormatter.swift +32 -0
  169. package/Sources/FoundationBridge/Localization.swift +149 -0
  170. package/Sources/FoundationBridge/Locks.swift +50 -0
  171. package/Sources/FoundationBridge/Markdown.swift +527 -0
  172. package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
  173. package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
  174. package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
  175. package/Sources/FoundationBridge/Operation.swift +195 -0
  176. package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
  177. package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
  178. package/Sources/FoundationBridge/SceneStorage.swift +78 -0
  179. package/Sources/FoundationBridge/SecurityExports.swift +8 -0
  180. package/Sources/FoundationBridge/Selector.swift +226 -0
  181. package/Sources/FoundationBridge/StringComparators.swift +17 -0
  182. package/Sources/FoundationBridge/Table.swift +211 -0
  183. package/Sources/FoundationBridge/TextAttributes.swift +42 -0
  184. package/Sources/FoundationBridge/Timer.swift +6 -1
  185. package/Sources/FoundationBridge/URLSession.swift +718 -0
  186. package/Sources/{_FoundationCommon → FoundationBridge}/UserDefaults.swift +17 -4
  187. package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
  188. package/Sources/FoundationBridge/WebSocket.swift +187 -0
  189. package/Sources/FoundationModels/FoundationModels.swift +1098 -0
  190. package/Sources/ImageIO/GIF.swift +72 -0
  191. package/Sources/ImageIO/ImageIO.swift +248 -0
  192. package/Sources/ImageIO/ImageTypes.swift +28 -0
  193. package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
  194. package/Sources/LocalAuthentication/LAContext.swift +86 -0
  195. package/Sources/MapKit/Geometry.swift +223 -0
  196. package/Sources/MapKit/Map.swift +638 -0
  197. package/Sources/MapKit/MapView.swift +229 -0
  198. package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
  199. package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
  200. package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
  201. package/Sources/OSLog/OSLog.swift +6 -0
  202. package/Sources/Photos/Photos.swift +572 -0
  203. package/Sources/PhotosUI/PhotosPicker.swift +248 -0
  204. package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
  205. package/Sources/QuickLook/QuickLook.swift +168 -0
  206. package/Sources/SafariServices/SafariServices.swift +106 -0
  207. package/Sources/Security/Security.swift +332 -0
  208. package/Sources/StoreKit/AppStore.swift +207 -0
  209. package/Sources/StoreKit/Products.swift +280 -0
  210. package/Sources/StoreKit/RequestReview.swift +28 -0
  211. package/Sources/StoreKit/StoreKit1.swift +486 -0
  212. package/Sources/StoreKit/StoreViews.swift +428 -0
  213. package/Sources/StoreKit/Transactions.swift +197 -0
  214. package/Sources/SwiftData/Macros.swift +58 -0
  215. package/Sources/SwiftData/ModelActor.swift +38 -0
  216. package/Sources/SwiftData/ModelContainer.swift +129 -0
  217. package/Sources/SwiftData/ModelContext.swift +451 -0
  218. package/Sources/SwiftData/PersistentModel.swift +238 -0
  219. package/Sources/SwiftData/Properties.swift +261 -0
  220. package/Sources/SwiftData/Query.swift +256 -0
  221. package/Sources/SwiftData/Schema.swift +192 -0
  222. package/Sources/SwiftData/Store.swift +146 -0
  223. package/Sources/SwiftData/StringPredicates.swift +125 -0
  224. package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
  225. package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
  226. package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
  227. package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
  228. package/Sources/SwiftDataMacros/Plugin.swift +18 -0
  229. package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
  230. package/Sources/SwiftUI/API/Accessibility.swift +55 -6
  231. package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
  232. package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
  233. package/Sources/SwiftUI/API/Alert.swift +1 -1
  234. package/Sources/SwiftUI/API/AlignmentGuides.swift +68 -0
  235. package/Sources/SwiftUI/API/Animation.swift +37 -5
  236. package/Sources/SwiftUI/API/App.swift +31 -1
  237. package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
  238. package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
  239. package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
  240. package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
  241. package/Sources/SwiftUI/API/Canvas.swift +337 -0
  242. package/Sources/SwiftUI/API/Color.swift +104 -28
  243. package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
  244. package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
  245. package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
  246. package/Sources/SwiftUI/API/Commands.swift +106 -0
  247. package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
  248. package/Sources/SwiftUI/API/ContentShape.swift +33 -0
  249. package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
  250. package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
  251. package/Sources/SwiftUI/API/Controls.swift +59 -27
  252. package/Sources/SwiftUI/API/CustomLayout.swift +49 -10
  253. package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
  254. package/Sources/SwiftUI/API/Decorations.swift +1 -1
  255. package/Sources/SwiftUI/API/EditMode.swift +25 -82
  256. package/Sources/SwiftUI/API/Effects.swift +125 -10
  257. package/Sources/SwiftUI/API/Entry.swift +8 -0
  258. package/Sources/SwiftUI/API/Environment.swift +100 -9
  259. package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
  260. package/Sources/SwiftUI/API/Focus.swift +11 -3
  261. package/Sources/SwiftUI/API/Gauge.swift +26 -10
  262. package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
  263. package/Sources/SwiftUI/API/GeometryReader.swift +13 -2
  264. package/Sources/SwiftUI/API/GestureState.swift +65 -0
  265. package/Sources/SwiftUI/API/Gestures.swift +1 -1
  266. package/Sources/SwiftUI/API/Glass.swift +127 -0
  267. package/Sources/SwiftUI/API/Grid.swift +1 -1
  268. package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
  269. package/Sources/SwiftUI/API/KeyPress.swift +54 -0
  270. package/Sources/SwiftUI/API/LabelStyle.swift +13 -6
  271. package/Sources/SwiftUI/API/Layout.swift +71 -12
  272. package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
  273. package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
  274. package/Sources/SwiftUI/API/Lists.swift +61 -6
  275. package/Sources/SwiftUI/API/Menu.swift +8 -1
  276. package/Sources/SwiftUI/API/Modifiers.swift +88 -12
  277. package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
  278. package/Sources/SwiftUI/API/Namespace.swift +44 -0
  279. package/Sources/SwiftUI/API/Navigation.swift +24 -9
  280. package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
  281. package/Sources/SwiftUI/API/ObservableObject.swift +16 -2
  282. package/Sources/SwiftUI/API/Path.swift +543 -0
  283. package/Sources/SwiftUI/API/Phase8Controls.swift +48 -31
  284. package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
  285. package/Sources/SwiftUI/API/Picker.swift +14 -4
  286. package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
  287. package/Sources/SwiftUI/API/Popover.swift +41 -0
  288. package/Sources/SwiftUI/API/Preferences.swift +262 -0
  289. package/Sources/SwiftUI/API/Presentation.swift +17 -4
  290. package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
  291. package/Sources/SwiftUI/API/Primitives.swift +168 -39
  292. package/Sources/SwiftUI/API/Publishers.swift +4 -4
  293. package/Sources/SwiftUI/API/Redaction.swift +75 -0
  294. package/Sources/SwiftUI/API/RowActions.swift +3 -2
  295. package/Sources/SwiftUI/API/Scenes.swift +131 -0
  296. package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
  297. package/Sources/SwiftUI/API/ScrollTargets.swift +3 -3
  298. package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
  299. package/Sources/SwiftUI/API/SectionSupplements.swift +86 -0
  300. package/Sources/SwiftUI/API/Shape.swift +214 -0
  301. package/Sources/SwiftUI/API/ShapeStyle.swift +187 -8
  302. package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
  303. package/Sources/SwiftUI/API/Sharing.swift +193 -0
  304. package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
  305. package/Sources/SwiftUI/API/State.swift +18 -1
  306. package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
  307. package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
  308. package/Sources/SwiftUI/API/TabContent.swift +841 -0
  309. package/Sources/SwiftUI/API/Table.swift +382 -0
  310. package/Sources/SwiftUI/API/Tabs.swift +148 -4
  311. package/Sources/SwiftUI/API/Tasks.swift +2 -2
  312. package/Sources/SwiftUI/API/Text.swift +386 -0
  313. package/Sources/SwiftUI/API/TextDates.swift +61 -0
  314. package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
  315. package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
  316. package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
  317. package/Sources/SwiftUI/API/Toolbar.swift +52 -16
  318. package/Sources/SwiftUI/API/Transfer.swift +145 -0
  319. package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
  320. package/Sources/SwiftUI/API/Video.swift +64 -0
  321. package/Sources/SwiftUI/API/View.swift +46 -2
  322. package/Sources/SwiftUI/API/ViewModifier.swift +4 -1
  323. package/Sources/SwiftUI/API/VisualEffect.swift +74 -1
  324. package/Sources/SwiftUI/API/Windows.swift +25 -0
  325. package/Sources/SwiftUI/Charts/Axis.swift +7 -1
  326. package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
  327. package/Sources/SwiftUI/Charts/Chart.swift +17 -3
  328. package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
  329. package/Sources/SwiftUI/Localization/Localization.swift +524 -0
  330. package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
  331. package/Sources/SwiftUI/Runtime/Executor.swift +2 -0
  332. package/Sources/SwiftUI/Runtime/Exports.swift +37 -1
  333. package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
  334. package/Sources/SwiftUI/Runtime/JSON.swift +76 -4
  335. package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
  336. package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
  337. package/Sources/SwiftUI/Runtime/Ops.swift +58 -12
  338. package/Sources/SwiftUI/Runtime/Reconciler.swift +10 -1
  339. package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
  340. package/Sources/SwiftUI/Runtime/Runtime.swift +977 -198
  341. package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
  342. package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
  343. package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
  344. package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
  345. package/Sources/Symbols/Symbols.swift +25 -0
  346. package/Sources/Translation/Translation.swift +423 -0
  347. package/Sources/UIKit/Activity.swift +213 -0
  348. package/Sources/UIKit/Alerts.swift +69 -0
  349. package/Sources/UIKit/AppDelegate.swift +222 -0
  350. package/Sources/UIKit/Appearance.swift +84 -0
  351. package/Sources/UIKit/ColorConversions.swift +70 -0
  352. package/Sources/UIKit/Controls.swift +225 -0
  353. package/Sources/UIKit/Device.swift +200 -0
  354. package/Sources/UIKit/Feedback.swift +65 -0
  355. package/Sources/UIKit/Font.swift +307 -0
  356. package/Sources/UIKit/Graphics.swift +204 -0
  357. package/Sources/UIKit/HostingController.swift +185 -0
  358. package/Sources/UIKit/Identity.swift +24 -0
  359. package/Sources/UIKit/Introspectable.swift +510 -0
  360. package/Sources/UIKit/Pasteboard.swift +363 -0
  361. package/Sources/UIKit/PhotoAlbum.swift +81 -0
  362. package/Sources/UIKit/RemoteNotifications.swift +15 -0
  363. package/Sources/UIKit/Representable.swift +288 -0
  364. package/Sources/UIKit/SafeArea.swift +12 -0
  365. package/Sources/UIKit/SceneDelegates.swift +132 -0
  366. package/Sources/UIKit/Scenes.swift +40 -0
  367. package/Sources/UIKit/ScrollView.swift +157 -0
  368. package/Sources/UIKit/ShortcutItems.swift +67 -0
  369. package/Sources/UIKit/SymbolConfiguration.swift +124 -0
  370. package/Sources/UIKit/TargetAction.swift +123 -0
  371. package/Sources/UIKit/TextPaste.swift +161 -0
  372. package/Sources/UIKit/TextView.swift +538 -0
  373. package/Sources/UIKit/UIKit.swift +292 -0
  374. package/Sources/UIKit/UIView.swift +855 -0
  375. package/Sources/UIKit/ViewTranslation.swift +311 -0
  376. package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
  377. package/Sources/UserNotifications/Content.swift +370 -0
  378. package/Sources/UserNotifications/NotificationCenter.swift +309 -0
  379. package/Sources/WeatherKit/WeatherKit.swift +228 -0
  380. package/Sources/WebKit/WebKit.swift +245 -0
  381. package/Sources/os/os.swift +376 -0
  382. package/Sources/zlib/zlib.swift +6 -0
  383. package/index.d.ts +1 -1
  384. package/index.mjs +2 -2
  385. package/manifest.d.mts +2 -0
  386. package/manifest.mjs +41 -0
  387. package/package.json +5 -3
  388. package/sync-sources.mjs +21 -7
  389. package/Sources/FoundationLite/Common.swift +0 -3
  390. package/Sources/FoundationLite/FoundationLite.swift +0 -171
  391. package/Sources/FoundationLite/Interaction.swift +0 -146
  392. package/Sources/FoundationLite/Timer.swift +0 -48
  393. package/Sources/_FoundationCommon/_FoundationCommon.swift +0 -10
@@ -0,0 +1,688 @@
1
+ // Capture for the browser, as far as code scanners use it: a session with
2
+ // the camera as its input, a metadata output that reports machine-readable
3
+ // codes, a photo output, and a preview layer (docs/ops-protocol.md, "Code
4
+ // scanning").
5
+ //
6
+ // The page owns the camera. `startRunning()` asks it to scan (a `scanner`
7
+ // host request with the metadata output's `BarcodeDetector` formats): it
8
+ // opens the camera over the page, or, where the browser cannot scan, asks the
9
+ // viewer to type the code. The code it answers with reaches the metadata
10
+ // output's delegate as an `AVMetadataMachineReadableCodeObject`, on the
11
+ // delegate's queue, as a frame with a code does on iOS. One scan per request:
12
+ // after a code, or when the viewer closes the camera, the session keeps
13
+ // running and its preview layer offers to scan again.
14
+ //
15
+ // The photo output's photo is the camera frame the code was read in (a JPEG
16
+ // the page sends with the code), or a one-pixel placeholder where there was
17
+ // none (a typed code, a headless run). Devices are the page's two cameras,
18
+ // back and front, each a wide-angle camera; their configuration (torch,
19
+ // focus, exposure, zoom) is kept, and the torch is asked of the page when it
20
+ // scans. Authorization is granted: the browser asks the viewer when the
21
+ // camera opens.
22
+
23
+ import Foundation
24
+ import FoundationBridge
25
+ import SwiftUI
26
+ import struct SwiftUI.CGFloat
27
+ import struct SwiftUI.CGPoint
28
+ import struct SwiftUI.CGRect
29
+ import UIKit
30
+
31
+ // MARK: - Devices
32
+
33
+ public enum AVAuthorizationStatus: Int, Sendable {
34
+ case notDetermined = 0, restricted, denied, authorized
35
+ }
36
+
37
+ /// A camera: the page's back or front camera.
38
+ open class AVCaptureDevice: @unchecked Sendable {
39
+ public struct DeviceType: RawRepresentable, Hashable, Sendable {
40
+ public let rawValue: String
41
+ public init(rawValue: String) { self.rawValue = rawValue }
42
+ public init(_ rawValue: String) { self.rawValue = rawValue }
43
+ public static let builtInWideAngleCamera = DeviceType("AVCaptureDeviceTypeBuiltInWideAngleCamera")
44
+ public static let builtInUltraWideCamera = DeviceType("AVCaptureDeviceTypeBuiltInUltraWideCamera")
45
+ public static let builtInTelephotoCamera = DeviceType("AVCaptureDeviceTypeBuiltInTelephotoCamera")
46
+ public static let builtInDualCamera = DeviceType("AVCaptureDeviceTypeBuiltInDualCamera")
47
+ public static let builtInDualWideCamera = DeviceType("AVCaptureDeviceTypeBuiltInDualWideCamera")
48
+ public static let builtInTripleCamera = DeviceType("AVCaptureDeviceTypeBuiltInTripleCamera")
49
+ public static let builtInTrueDepthCamera = DeviceType("AVCaptureDeviceTypeBuiltInTrueDepthCamera")
50
+ public static let builtInLiDARDepthCamera = DeviceType("AVCaptureDeviceTypeBuiltInLiDARDepthCamera")
51
+ public static let builtInMicrophone = DeviceType("AVCaptureDeviceTypeBuiltInMicrophone")
52
+ public static let microphone = DeviceType("AVCaptureDeviceTypeMicrophone")
53
+ public static let external = DeviceType("AVCaptureDeviceTypeExternal")
54
+ }
55
+
56
+ public enum Position: Int, Sendable { case unspecified = 0, back, front }
57
+ public enum TorchMode: Int, Sendable { case off = 0, on, auto }
58
+ public enum FlashMode: Int, Sendable { case off = 0, on, auto }
59
+ public enum FocusMode: Int, Sendable { case locked = 0, autoFocus, continuousAutoFocus }
60
+ public enum ExposureMode: Int, Sendable { case locked = 0, autoExpose, continuousAutoExposure, custom }
61
+
62
+ /// A capture format: a 1920 × 1080 video stream with a 65° field of view.
63
+ open class Format: @unchecked Sendable {
64
+ public let formatDescription = CMFormatDescription(dimensions: CMVideoDimensions(width: 1920, height: 1080))
65
+ public let videoFieldOfView: Float = 65
66
+ public let videoMaxZoomFactor: CGFloat = 16
67
+ init() {}
68
+ }
69
+
70
+ public let deviceType: DeviceType
71
+ public let position: Position
72
+ public let uniqueID: String
73
+ public let localizedName: String
74
+ public let activeFormat = Format()
75
+ public var formats: [Format] { [activeFormat] }
76
+
77
+ /// Asked of the page when it scans (a camera track's torch, where it has one).
78
+ open var torchMode: TorchMode = .off
79
+ open var hasTorch: Bool { position == .back }
80
+ open var isTorchAvailable: Bool { hasTorch }
81
+ open var isTorchActive: Bool { torchMode == .on }
82
+ open var torchLevel: Float { torchMode == .on ? 1 : 0 }
83
+ open var hasFlash: Bool { false }
84
+ open var focusMode: FocusMode = .continuousAutoFocus
85
+ open var exposureMode: ExposureMode = .continuousAutoExposure
86
+ open var focusPointOfInterest = CGPoint(x: 0.5, y: 0.5)
87
+ open var exposurePointOfInterest = CGPoint(x: 0.5, y: 0.5)
88
+ /// The page does not focus on a point.
89
+ open var isFocusPointOfInterestSupported: Bool { false }
90
+ open var isExposurePointOfInterestSupported: Bool { false }
91
+ open var isSmoothAutoFocusSupported: Bool { false }
92
+ open var isSmoothAutoFocusEnabled = false
93
+ open var autoFocusRangeRestriction = 0
94
+ /// Not known: -1, as for a camera that does not report it.
95
+ open var minimumFocusDistance: Int { -1 }
96
+ open var videoZoomFactor: CGFloat = 1
97
+ open var minAvailableVideoZoomFactor: CGFloat { 1 }
98
+ open var maxAvailableVideoZoomFactor: CGFloat { activeFormat.videoMaxZoomFactor }
99
+ open var isConnected: Bool { true }
100
+
101
+
102
+ init(position: Position) {
103
+ deviceType = .builtInWideAngleCamera
104
+ self.position = position
105
+ uniqueID = position == .front ? "browser-camera-front" : "browser-camera-back"
106
+ localizedName = position == .front ? "Front Camera" : "Back Camera"
107
+ }
108
+
109
+ static let back = AVCaptureDevice(position: .back)
110
+ static let front = AVCaptureDevice(position: .front)
111
+
112
+ /// The back camera for video; nil for anything else.
113
+ open class func `default`(for mediaType: AVMediaType) -> AVCaptureDevice? {
114
+ mediaType == .video ? back : nil
115
+ }
116
+
117
+ open class func `default`(_ deviceType: DeviceType, for mediaType: AVMediaType?, position: Position) -> AVCaptureDevice? {
118
+ guard deviceType == .builtInWideAngleCamera, mediaType == nil || mediaType == .video else { return nil }
119
+ return position == .front ? front : back
120
+ }
121
+
122
+ open class func authorizationStatus(for mediaType: AVMediaType) -> AVAuthorizationStatus { .authorized }
123
+
124
+ /// Granted (the browser asks when the camera opens), on the main queue.
125
+ /// The handler is not `@Sendable`, as Objective-C's block is not.
126
+ open class func requestAccess(for mediaType: AVMediaType, completionHandler handler: @escaping (Bool) -> Void) {
127
+ nonisolated(unsafe) let handler = handler
128
+ FoundationBridge.DispatchQueue.main.async { handler(true) }
129
+ }
130
+
131
+ @available(*, deprecated, message: "Use AVCaptureDevice.DiscoverySession")
132
+ open class func devices(for mediaType: AVMediaType) -> [AVCaptureDevice] {
133
+ mediaType == .video ? [back, front] : []
134
+ }
135
+
136
+ /// The cameras of the given types, media type and position.
137
+ open class DiscoverySession: @unchecked Sendable {
138
+ public let devices: [AVCaptureDevice]
139
+
140
+ public init(deviceTypes: [DeviceType], mediaType: AVMediaType?, position: Position) {
141
+ guard deviceTypes.contains(.builtInWideAngleCamera), mediaType == nil || mediaType == .video else {
142
+ devices = []
143
+ return
144
+ }
145
+ switch position {
146
+ case .back: devices = [AVCaptureDevice.back]
147
+ case .front: devices = [AVCaptureDevice.front]
148
+ case .unspecified: devices = [AVCaptureDevice.back, AVCaptureDevice.front]
149
+ }
150
+ }
151
+ }
152
+
153
+ open func hasMediaType(_ mediaType: AVMediaType) -> Bool { mediaType == .video }
154
+ open func lockForConfiguration() throws {}
155
+ open func unlockForConfiguration() {}
156
+ open func isTorchModeSupported(_ torchMode: TorchMode) -> Bool { hasTorch }
157
+ open func setTorchModeOn(level torchLevel: Float) throws { torchMode = .on }
158
+ open func isFocusModeSupported(_ focusMode: FocusMode) -> Bool { true }
159
+ open func isExposureModeSupported(_ exposureMode: ExposureMode) -> Bool { true }
160
+ open func ramp(toVideoZoomFactor factor: CGFloat, withRate rate: Float) { videoZoomFactor = factor }
161
+ open func cancelVideoZoomRamp() {}
162
+ }
163
+
164
+ // MARK: - Core Media's format descriptions
165
+
166
+ /// The pixel size of a video format.
167
+ public struct CMVideoDimensions: Hashable, Sendable {
168
+ public var width: Int32
169
+ public var height: Int32
170
+ public init(width: Int32, height: Int32) {
171
+ self.width = width
172
+ self.height = height
173
+ }
174
+ }
175
+
176
+ /// A media format's description: here, a video stream's size.
177
+ public final class CMFormatDescription: @unchecked Sendable {
178
+ let dimensions: CMVideoDimensions
179
+ init(dimensions: CMVideoDimensions) { self.dimensions = dimensions }
180
+ }
181
+
182
+ public typealias CMVideoFormatDescription = CMFormatDescription
183
+
184
+ public func CMVideoFormatDescriptionGetDimensions(_ videoDesc: CMFormatDescription) -> CMVideoDimensions { videoDesc.dimensions }
185
+
186
+ // MARK: - Inputs, outputs and connections
187
+
188
+ open class AVCaptureInput: @unchecked Sendable {
189
+ init() {}
190
+ }
191
+
192
+ /// A camera as a session's input.
193
+ open class AVCaptureDeviceInput: AVCaptureInput, @unchecked Sendable {
194
+ public let device: AVCaptureDevice
195
+
196
+ public init(device: AVCaptureDevice) throws {
197
+ self.device = device
198
+ super.init()
199
+ }
200
+ }
201
+
202
+ public enum AVCaptureVideoOrientation: Int, Sendable {
203
+ case portrait = 1, portraitUpsideDown, landscapeRight, landscapeLeft
204
+ }
205
+
206
+ /// What links a session's input to one of its outputs (or a preview layer).
207
+ open class AVCaptureConnection: @unchecked Sendable {
208
+ public private(set) weak var output: AVCaptureOutput?
209
+ open var isEnabled = true
210
+ open var isActive: Bool { true }
211
+ open var isVideoOrientationSupported: Bool { true }
212
+ open var videoOrientation: AVCaptureVideoOrientation = .portrait
213
+ open var videoRotationAngle: CGFloat = 90
214
+ open var isVideoMirroringSupported: Bool { true }
215
+ open var isVideoMirrored = false
216
+ open var automaticallyAdjustsVideoMirroring = true
217
+
218
+ init(output: AVCaptureOutput?) { self.output = output }
219
+
220
+ open func isVideoRotationAngleSupported(_ videoRotationAngle: CGFloat) -> Bool { true }
221
+ }
222
+
223
+ open class AVCaptureOutput: @unchecked Sendable {
224
+ public internal(set) var connections: [AVCaptureConnection] = []
225
+ weak var session: AVCaptureSession?
226
+
227
+ init() {}
228
+
229
+ open func connection(with mediaType: AVMediaType) -> AVCaptureConnection? {
230
+ mediaType == .video ? connections.first : nil
231
+ }
232
+ }
233
+
234
+ // MARK: - Metadata
235
+
236
+ /// Something a capture found in a frame; codes are `AVMetadataMachineReadableCodeObject`s.
237
+ open class AVMetadataObject: @unchecked Sendable {
238
+ /// The kinds of machine-readable code (Apple's raw values).
239
+ public struct ObjectType: RawRepresentable, Hashable, Sendable {
240
+ public let rawValue: String
241
+ public init(rawValue: String) { self.rawValue = rawValue }
242
+ public init(_ rawValue: String) { self.rawValue = rawValue }
243
+
244
+ public static let qr = ObjectType(rawValue: "org.iso.QRCode")
245
+ public static let aztec = ObjectType(rawValue: "org.iso.Aztec")
246
+ public static let dataMatrix = ObjectType(rawValue: "org.iso.DataMatrix")
247
+ public static let pdf417 = ObjectType(rawValue: "org.iso.PDF417")
248
+ public static let microQR = ObjectType(rawValue: "org.iso.MicroQR")
249
+ public static let microPDF417 = ObjectType(rawValue: "org.iso.MicroPDF417")
250
+ public static let code39 = ObjectType(rawValue: "org.iso.Code39")
251
+ public static let code39Mod43 = ObjectType(rawValue: "org.iso.Code39Mod43")
252
+ public static let code93 = ObjectType(rawValue: "com.intermec.Code93")
253
+ public static let code128 = ObjectType(rawValue: "org.iso.Code128")
254
+ public static let ean8 = ObjectType(rawValue: "org.gs1.EAN-8")
255
+ public static let ean13 = ObjectType(rawValue: "org.gs1.EAN-13")
256
+ public static let upce = ObjectType(rawValue: "org.gs1.UPC-E")
257
+ public static let interleaved2of5 = ObjectType(rawValue: "org.ansi.Interleaved2of5")
258
+ public static let itf14 = ObjectType(rawValue: "org.gs1.ITF14")
259
+ public static let codabar = ObjectType(rawValue: "org.codabar")
260
+ public static let gs1DataBar = ObjectType(rawValue: "org.gs1.GS1DataBar")
261
+ public static let gs1DataBarExpanded = ObjectType(rawValue: "org.gs1.GS1DataBarExpanded")
262
+ public static let gs1DataBarLimited = ObjectType(rawValue: "org.gs1.GS1DataBarLimited")
263
+ public static let face = ObjectType(rawValue: "face")
264
+ public static let humanBody = ObjectType(rawValue: "mdta/com.apple.quicktime.detected-human-body")
265
+
266
+ /// Every code type the page's `BarcodeDetector` can look for.
267
+ static let codes: [ObjectType] = [.qr, .microQR, .aztec, .dataMatrix, .pdf417, .microPDF417, .code39, .code39Mod43,
268
+ .code93, .code128, .ean8, .ean13, .upce, .interleaved2of5, .itf14, .codabar]
269
+
270
+ /// The `BarcodeDetector` format that finds this kind of code, if any.
271
+ public var _barcodeFormat: String? {
272
+ switch self {
273
+ case .qr, .microQR: "qr_code"
274
+ case .aztec: "aztec"
275
+ case .dataMatrix: "data_matrix"
276
+ case .pdf417, .microPDF417: "pdf417"
277
+ case .code39, .code39Mod43: "code_39"
278
+ case .code93: "code_93"
279
+ case .code128: "code_128"
280
+ case .ean8: "ean_8"
281
+ case .ean13: "ean_13"
282
+ case .upce: "upc_e"
283
+ case .interleaved2of5, .itf14: "itf"
284
+ case .codabar: "codabar"
285
+ default: nil
286
+ }
287
+ }
288
+ }
289
+
290
+ public let type: ObjectType
291
+ public let bounds: CGRect
292
+ public let time: CMTime
293
+ public let duration: CMTime
294
+
295
+ init(type: ObjectType, bounds: CGRect) {
296
+ self.type = type
297
+ self.bounds = bounds
298
+ time = .zero
299
+ duration = .zero
300
+ }
301
+ }
302
+
303
+ /// A code read in a frame: its contents and corners.
304
+ open class AVMetadataMachineReadableCodeObject: AVMetadataObject, @unchecked Sendable {
305
+ public let stringValue: String?
306
+ /// The code's corners, in the frame's pixels as the page reports them.
307
+ public let corners: [CGPoint]
308
+
309
+ public init(type: ObjectType, stringValue: String?, corners: [CGPoint]) {
310
+ self.stringValue = stringValue
311
+ self.corners = corners
312
+ let xs = corners.map(\.x), ys = corners.map(\.y)
313
+ let bounds = corners.isEmpty ? CGRect.zero
314
+ : CGRect(x: xs.min()!, y: ys.min()!, width: xs.max()! - xs.min()!, height: ys.max()! - ys.min()!)
315
+ super.init(type: type, bounds: bounds)
316
+ }
317
+ }
318
+
319
+ /// Main-actor isolated: the page has one thread, and a view controller (as
320
+ /// CodeScanner's is) conforms in Swift 6 as it may to Objective-C's protocol.
321
+ @MainActor
322
+ public protocol AVCaptureMetadataOutputObjectsDelegate: AnyObject {
323
+ func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)
324
+ }
325
+
326
+ extension AVCaptureMetadataOutputObjectsDelegate {
327
+ public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {}
328
+ }
329
+
330
+ /// Reports the codes the page reads to its delegate.
331
+ open class AVCaptureMetadataOutput: AVCaptureOutput, @unchecked Sendable {
332
+ public private(set) weak var metadataObjectsDelegate: (any AVCaptureMetadataOutputObjectsDelegate)?
333
+ public private(set) var metadataObjectsCallbackQueue: FoundationBridge.DispatchQueue?
334
+ /// The kinds of code to look for; only kinds the page can read are available.
335
+ open var metadataObjectTypes: [AVMetadataObject.ObjectType]! = []
336
+ open var availableMetadataObjectTypes: [AVMetadataObject.ObjectType] { session == nil ? [] : AVMetadataObject.ObjectType.codes }
337
+ open var rectOfInterest = CGRect(x: 0, y: 0, width: 1, height: 1)
338
+
339
+ public override init() { super.init() }
340
+
341
+ open func setMetadataObjectsDelegate(_ objectsDelegate: (any AVCaptureMetadataOutputObjectsDelegate)?, queue objectsCallbackQueue: FoundationBridge.DispatchQueue?) {
342
+ metadataObjectsDelegate = objectsDelegate
343
+ metadataObjectsCallbackQueue = objectsCallbackQueue
344
+ session?.outputChanged()
345
+ }
346
+
347
+ /// The page's formats for the requested kinds of code.
348
+ var barcodeFormats: [String] {
349
+ var formats: [String] = []
350
+ for type in metadataObjectTypes ?? [] {
351
+ if let format = type._barcodeFormat, !formats.contains(format) { formats.append(format) }
352
+ }
353
+ return formats
354
+ }
355
+
356
+ /// The kind of code `format` is among the requested ones (UPC-A, which
357
+ /// `BarcodeDetector` reports on its own, is EAN-13 to AVFoundation).
358
+ func objectType(forFormat format: String?) -> AVMetadataObject.ObjectType {
359
+ let types = metadataObjectTypes ?? []
360
+ let wanted = format == "upc_a" ? "ean_13" : format
361
+ return types.first { $0._barcodeFormat == wanted } ?? types.first ?? .qr
362
+ }
363
+
364
+ func deliver(_ object: AVMetadataObject) {
365
+ guard let delegate = metadataObjectsDelegate, let connection = connections.first else { return }
366
+ nonisolated(unsafe) let held = (delegate, object, connection)
367
+ let send: @Sendable () -> Void = { MainActor.assumeIsolated { held.0.metadataOutput(self, didOutput: [held.1], from: held.2) } }
368
+ if let queue = metadataObjectsCallbackQueue { queue.async(execute: send) } else { send() }
369
+ }
370
+ }
371
+
372
+ // MARK: - Photos
373
+
374
+ open class AVCapturePhotoSettings: @unchecked Sendable {
375
+ public let uniqueID: Int64
376
+ open var flashMode: AVCaptureDevice.FlashMode = .off
377
+ open var isHighResolutionPhotoEnabled = false
378
+ nonisolated(unsafe) private static var serial: Int64 = 0
379
+
380
+ public init() {
381
+ Self.serial += 1
382
+ uniqueID = Self.serial
383
+ }
384
+
385
+ public convenience init(from photoSettings: AVCapturePhotoSettings) {
386
+ self.init()
387
+ flashMode = photoSettings.flashMode
388
+ }
389
+ }
390
+
391
+ open class AVCaptureResolvedPhotoSettings: @unchecked Sendable {
392
+ public let uniqueID: Int64
393
+ init(uniqueID: Int64) { self.uniqueID = uniqueID }
394
+ }
395
+
396
+ /// A captured photo: the frame the last code was read in.
397
+ open class AVCapturePhoto: @unchecked Sendable {
398
+ let data: Data
399
+ public let resolvedSettings: AVCaptureResolvedPhotoSettings
400
+ public let timestamp = CMTime.zero
401
+ public var isRawPhoto: Bool { false }
402
+
403
+ init(data: Data, resolvedSettings: AVCaptureResolvedPhotoSettings) {
404
+ self.data = data
405
+ self.resolvedSettings = resolvedSettings
406
+ }
407
+
408
+ open func fileDataRepresentation() -> Data? { data }
409
+ open func cgImageRepresentation() -> CGImage? { UIImage(data: data)?.cgImage }
410
+ }
411
+
412
+ /// Main-actor isolated, as `AVCaptureMetadataOutputObjectsDelegate` is.
413
+ @MainActor
414
+ public protocol AVCapturePhotoCaptureDelegate: AnyObject {
415
+ func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings)
416
+ func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings)
417
+ func photoOutput(_ output: AVCapturePhotoOutput, didCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings)
418
+ func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: (any Error)?)
419
+ func photoOutput(_ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: (any Error)?)
420
+ }
421
+
422
+ extension AVCapturePhotoCaptureDelegate {
423
+ public func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) {}
424
+ public func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {}
425
+ public func photoOutput(_ output: AVCapturePhotoOutput, didCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {}
426
+ public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: (any Error)?) {}
427
+ public func photoOutput(_ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: (any Error)?) {}
428
+ }
429
+
430
+ /// Takes a photo: the camera frame of the last code the session read, on the main queue.
431
+ open class AVCapturePhotoOutput: AVCaptureOutput, @unchecked Sendable {
432
+ open var isHighResolutionCaptureEnabled = false
433
+ open var maxPhotoQualityPrioritization = 0
434
+ open var supportedFlashModes: [AVCaptureDevice.FlashMode] { [.off] }
435
+
436
+ public override init() { super.init() }
437
+
438
+ open func capturePhoto(with settings: AVCapturePhotoSettings, delegate: any AVCapturePhotoCaptureDelegate) {
439
+ let resolved = AVCaptureResolvedPhotoSettings(uniqueID: settings.uniqueID)
440
+ let photo = AVCapturePhoto(data: session?.lastFrame ?? _placeholderPhoto, resolvedSettings: resolved)
441
+ nonisolated(unsafe) let held = delegate
442
+ FoundationBridge.DispatchQueue.main.async {
443
+ MainActor.assumeIsolated {
444
+ held.photoOutput(self, willBeginCaptureFor: resolved)
445
+ held.photoOutput(self, willCapturePhotoFor: resolved)
446
+ held.photoOutput(self, didCapturePhotoFor: resolved)
447
+ held.photoOutput(self, didFinishProcessingPhoto: photo, error: nil)
448
+ held.photoOutput(self, didFinishCaptureFor: resolved, error: nil)
449
+ }
450
+ }
451
+ }
452
+ }
453
+
454
+ /// A one-pixel white PNG: the photo when no frame came with the code.
455
+ let _placeholderPhoto = Data(base64Encoded: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4//8/AAX+Av4N70a4AAAAAElFTkSuQmCC")!
456
+
457
+ // MARK: - Sessions
458
+
459
+ /// A capture session: while it runs, the page scans for its metadata output.
460
+ open class AVCaptureSession: @unchecked Sendable {
461
+ public struct Preset: RawRepresentable, Hashable, Sendable {
462
+ public let rawValue: String
463
+ public init(rawValue: String) { self.rawValue = rawValue }
464
+ public static let high = Preset(rawValue: "AVCaptureSessionPresetHigh")
465
+ public static let medium = Preset(rawValue: "AVCaptureSessionPresetMedium")
466
+ public static let low = Preset(rawValue: "AVCaptureSessionPresetLow")
467
+ public static let photo = Preset(rawValue: "AVCaptureSessionPresetPhoto")
468
+ public static let hd1280x720 = Preset(rawValue: "AVCaptureSessionPreset1280x720")
469
+ public static let hd1920x1080 = Preset(rawValue: "AVCaptureSessionPreset1920x1080")
470
+ public static let vga640x480 = Preset(rawValue: "AVCaptureSessionPreset640x480")
471
+ }
472
+
473
+ /// Where the session is with the page's scanner, drawn by its preview layers.
474
+ public enum _ScanState: Equatable, Sendable {
475
+ /// Not running, or waiting to be asked to scan again.
476
+ case idle
477
+ /// The page is scanning (its camera or a typed code is up).
478
+ case scanning
479
+ /// The last scan delivered a code.
480
+ case found
481
+ /// The page could not scan; the message says why.
482
+ case failed(String)
483
+ }
484
+
485
+ open var sessionPreset: Preset = .high
486
+ public private(set) var inputs: [AVCaptureInput] = []
487
+ public private(set) var outputs: [AVCaptureOutput] = []
488
+ public private(set) var isRunning = false
489
+ public private(set) var _scanState: _ScanState = .idle { didSet { if _scanState != oldValue { notifyPreviews() } } }
490
+ /// The camera frame of the last code the page read (a JPEG), for photo outputs.
491
+ var lastFrame: Data?
492
+ private var previews: [WeakPreview] = []
493
+
494
+ public init() {}
495
+
496
+ open var connections: [AVCaptureConnection] { outputs.flatMap(\.connections) }
497
+
498
+ open func canAddInput(_ input: AVCaptureInput) -> Bool { !inputs.contains { $0 === input } }
499
+ open func addInput(_ input: AVCaptureInput) { if canAddInput(input) { inputs.append(input) } }
500
+ open func removeInput(_ input: AVCaptureInput) { inputs.removeAll { $0 === input } }
501
+
502
+ open func canAddOutput(_ output: AVCaptureOutput) -> Bool { !outputs.contains { $0 === output } && output.session == nil }
503
+
504
+ open func addOutput(_ output: AVCaptureOutput) {
505
+ guard canAddOutput(output) else { return }
506
+ outputs.append(output)
507
+ output.session = self
508
+ output.connections = [AVCaptureConnection(output: output)]
509
+ outputChanged()
510
+ }
511
+
512
+ open func removeOutput(_ output: AVCaptureOutput) {
513
+ outputs.removeAll { $0 === output }
514
+ output.session = nil
515
+ output.connections = []
516
+ }
517
+
518
+ open func beginConfiguration() {}
519
+ open func commitConfiguration() {}
520
+
521
+ /// Starts the session; the page is asked to scan for the metadata output.
522
+ open func startRunning() {
523
+ guard !isRunning else { return }
524
+ isRunning = true
525
+ _scanState = .idle
526
+ _scan()
527
+ }
528
+
529
+ /// Stops the session. A scan the page has open finishes; its code is dropped.
530
+ open func stopRunning() {
531
+ guard isRunning else { return }
532
+ isRunning = false
533
+ if _scanState != .scanning { _scanState = .idle }
534
+ }
535
+
536
+ /// A metadata output that wants codes, if the session has a camera.
537
+ private var scanningOutput: AVCaptureMetadataOutput? {
538
+ guard inputs.contains(where: { $0 is AVCaptureDeviceInput }) else { return nil }
539
+ return outputs.lazy.compactMap { $0 as? AVCaptureMetadataOutput }.first {
540
+ $0.metadataObjectsDelegate != nil && !$0.barcodeFormats.isEmpty
541
+ }
542
+ }
543
+
544
+ private var camera: AVCaptureDevice? {
545
+ inputs.lazy.compactMap { ($0 as? AVCaptureDeviceInput)?.device }.first
546
+ }
547
+
548
+ /// Asks the page for a code (see the top of the file); the preview
549
+ /// layer's button calls it again after a scan.
550
+ public func _scan() {
551
+ guard isRunning, _scanState != .scanning, let output = scanningOutput else { return }
552
+ _scanState = .scanning
553
+ let params: _JSON = .object([
554
+ "action": .string("scan"),
555
+ "formats": .array(output.barcodeFormats.map { .string($0) }),
556
+ "torch": .bool(camera?.torchMode == .on),
557
+ "vibrate": .bool(false),
558
+ "facing": .string(camera?.position == .front ? "user" : "environment"),
559
+ ])
560
+ Task { @MainActor in
561
+ do {
562
+ let answer = try await _CaptureHost.request(params)
563
+ self.finishScan(answer, output: output)
564
+ } catch {
565
+ let message = (error as? _HostRequestError)?.message ?? String(describing: error)
566
+ self._scanState = self.isRunning ? .failed(message) : .idle
567
+ }
568
+ }
569
+ }
570
+
571
+ private func finishScan(_ answer: _JSON, output: AVCaptureMetadataOutput) {
572
+ guard isRunning, case .object(let fields) = answer, case .string(let string)? = fields["string"] else {
573
+ _scanState = .idle
574
+ return
575
+ }
576
+ var format: String?
577
+ if case .string(let value)? = fields["format"] { format = value }
578
+ var corners: [CGPoint] = []
579
+ if case .array(let points)? = fields["corners"] {
580
+ for point in points {
581
+ if case .object(let xy) = point, case .number(let x)? = xy["x"], case .number(let y)? = xy["y"] {
582
+ corners.append(CGPoint(x: x, y: y))
583
+ }
584
+ }
585
+ }
586
+ lastFrame = nil
587
+ if case .string(let image)? = fields["image"] { lastFrame = Data(base64Encoded: image) }
588
+ _scanState = .found
589
+ output.deliver(AVMetadataMachineReadableCodeObject(type: output.objectType(forFormat: format), stringValue: string, corners: corners))
590
+ }
591
+
592
+ func outputChanged() {
593
+ // A delegate set after `startRunning()` (from another queue on iOS) starts the scan.
594
+ if isRunning, _scanState == .idle { _scan() }
595
+ }
596
+
597
+ fileprivate func register(_ preview: AVCaptureVideoPreviewLayer) {
598
+ previews.removeAll { $0.layer == nil || $0.layer === preview }
599
+ previews.append(WeakPreview(layer: preview))
600
+ }
601
+
602
+ private func notifyPreviews() {
603
+ for preview in previews { preview.layer?._changed() }
604
+ }
605
+
606
+ private struct WeakPreview {
607
+ weak var layer: AVCaptureVideoPreviewLayer?
608
+ }
609
+ }
610
+
611
+ /// Sends a `scanner` host request; tests substitute it.
612
+ @MainActor public enum _CaptureHost {
613
+ public static var request: (_ params: _JSON) async throws -> _JSON = { params in
614
+ try await _Runtime.shared._hostRequest(kind: "scanner", params: params)
615
+ }
616
+ }
617
+
618
+ // MARK: - Preview
619
+
620
+ /// Shows a session: the page's camera is over the page while it scans, so
621
+ /// the layer draws what to do next, filling its view (a button to scan again
622
+ /// after a code, or after the viewer closed the camera).
623
+ open class AVCaptureVideoPreviewLayer: CALayer, @unchecked Sendable {
624
+ open var session: AVCaptureSession? { didSet { if let session { session.register(self) }; _changed() } }
625
+ open var videoGravity: AVLayerVideoGravity = .resizeAspect
626
+ public private(set) lazy var connection: AVCaptureConnection? = AVCaptureConnection(output: nil)
627
+
628
+ public required init() { super.init() }
629
+
630
+ public init(session: AVCaptureSession) {
631
+ super.init()
632
+ self.session = session
633
+ session.register(self)
634
+ }
635
+
636
+ public init(sessionWithNoConnection session: AVCaptureSession) {
637
+ super.init()
638
+ self.session = session
639
+ session.register(self)
640
+ }
641
+
642
+ open func setSessionWithNoConnection(_ session: AVCaptureSession) { self.session = session }
643
+
644
+ /// Layer and capture coordinates are the same here (the page has the frames).
645
+ open func captureDevicePointConverted(fromLayerPoint pointInLayer: CGPoint) -> CGPoint { pointInLayer }
646
+ open func layerPointConverted(fromCaptureDevicePoint captureDevicePointOfInterest: CGPoint) -> CGPoint { captureDevicePointOfInterest }
647
+ open func metadataOutputRectConverted(fromLayerRect rectInLayerCoordinates: CGRect) -> CGRect { rectInLayerCoordinates }
648
+ open func layerRectConverted(fromMetadataOutputRect rectInMetadataOutputCoordinates: CGRect) -> CGRect { rectInMetadataOutputCoordinates }
649
+ open func transformedMetadataObject(for metadataObject: AVMetadataObject) -> AVMetadataObject? { metadataObject }
650
+
651
+ open override var _drawing: AnyView? {
652
+ guard let session else { return nil }
653
+ return AnyView(_CapturePreview(state: session.isRunning ? session._scanState : .idle, running: session.isRunning) { [weak session] in
654
+ session?._scan()
655
+ })
656
+ }
657
+ }
658
+
659
+ /// What a preview layer draws: black, as a camera preview starts, and what to do next.
660
+ struct _CapturePreview: View {
661
+ let state: AVCaptureSession._ScanState
662
+ let running: Bool
663
+ let scan: @MainActor @Sendable () -> Void
664
+
665
+ var body: some View {
666
+ ZStack {
667
+ Color.black
668
+ VStack(spacing: 16) {
669
+ switch state {
670
+ case .scanning:
671
+ ProgressView().tint(.white)
672
+ Text("Scanning…").foregroundColor(.white)
673
+ case .failed(let message):
674
+ Image(systemName: "camera.badge.ellipsis").font(.largeTitle).foregroundColor(.white)
675
+ Text(message).font(.footnote).foregroundColor(.white).multilineTextAlignment(.center)
676
+ Button("Try Again", systemImage: "arrow.clockwise", action: scan).buttonStyle(.borderedProminent)
677
+ case .idle, .found:
678
+ if running {
679
+ Image(systemName: "qrcode.viewfinder").font(.system(size: 64)).foregroundColor(.white)
680
+ Button(state == .found ? "Scan Again" : "Scan a Code", systemImage: "camera", action: scan)
681
+ .buttonStyle(.borderedProminent)
682
+ }
683
+ }
684
+ }
685
+ .padding(24)
686
+ }
687
+ }
688
+ }