@swiftbrowser/swift 0.0.0-stage → 0.2.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.
- package/Package.swift +214 -0
- package/README.md +10 -2
- package/Sources/AVFoundation/AVFoundation.swift +131 -0
- package/Sources/AVFoundation/Asset.swift +487 -0
- package/Sources/AVFoundation/AudioSession.swift +144 -0
- package/Sources/AVFoundation/CMTime.swift +303 -0
- package/Sources/AVFoundation/Capture.swift +688 -0
- package/Sources/AVFoundation/Player.swift +749 -0
- package/Sources/AVFoundation/PlayerView.swift +117 -0
- package/Sources/AVKit/AVKit.swift +132 -0
- package/Sources/Accelerate/Accelerate.swift +122 -0
- package/Sources/AppIntents/AppIntents.swift +144 -0
- package/Sources/AppIntents/Parameters.swift +220 -0
- package/Sources/AppIntents/Shortcuts.swift +159 -0
- package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
- package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
- package/Sources/AuthenticationServices/Authorization.swift +251 -0
- package/Sources/Charts/Charts.swift +61 -0
- package/Sources/Combine/AnyCancellable.swift +65 -0
- package/Sources/Combine/AnyPublisher.swift +148 -0
- package/Sources/Combine/AnySubscriber.swift +230 -0
- package/Sources/Combine/Cancellable.swift +35 -0
- package/Sources/Combine/Codable.swift +29 -0
- package/Sources/Combine/CombineIdentifier.swift +45 -0
- package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
- package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
- package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
- package/Sources/Combine/CurrentValueSubject.swift +252 -0
- package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
- package/Sources/Combine/Future.swift +228 -0
- package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
- package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
- package/Sources/Combine/Helpers/ConduitList.swift +59 -0
- package/Sources/Combine/Helpers/DebugHook.swift +177 -0
- package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
- package/Sources/Combine/Helpers/Locking.swift +30 -0
- package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
- package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
- package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
- package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
- package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
- package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
- package/Sources/Combine/Helpers/Utils.swift +30 -0
- package/Sources/Combine/Helpers/Violations.swift +33 -0
- package/Sources/Combine/ImmediateScheduler.swift +178 -0
- package/Sources/Combine/LICENSE +21 -0
- package/Sources/Combine/NotificationPublisher.swift +48 -0
- package/Sources/Combine/ObjectWillChange.swift +46 -0
- package/Sources/Combine/PassthroughSubject.swift +222 -0
- package/Sources/Combine/Publisher+Subscribe.swift +53 -0
- package/Sources/Combine/Publishers/Deferred.swift +48 -0
- package/Sources/Combine/Publishers/Empty.swift +54 -0
- package/Sources/Combine/Publishers/Fail.swift +42 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
- package/Sources/Combine/Publishers/Just.swift +313 -0
- package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
- package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
- package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
- package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
- package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
- package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
- package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
- package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
- package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
- package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
- package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
- package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
- package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
- package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
- package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
- package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
- package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
- package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
- package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
- package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
- package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
- package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
- package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
- package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
- package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
- package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
- package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
- package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
- package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
- package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
- package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
- package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
- package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
- package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
- package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
- package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
- package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
- package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
- package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
- package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
- package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
- package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
- package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
- package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
- package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
- package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
- package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
- package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
- package/Sources/Combine/Publishers/Publishers.swift +13 -0
- package/Sources/Combine/Publishers/Record.swift +237 -0
- package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
- package/Sources/Combine/Result.swift +46 -0
- package/Sources/Combine/Scheduler.swift +89 -0
- package/Sources/Combine/Schedulers.swift +211 -0
- package/Sources/Combine/Subject+Void.swift +17 -0
- package/Sources/Combine/Subscriber+Void.swift +20 -0
- package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
- package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
- package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
- package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
- package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
- package/Sources/Combine/Subscription.swift +22 -0
- package/Sources/Combine/Subscriptions.swift +42 -0
- package/Sources/Combine/SwiftUIObservation.swift +10 -0
- package/Sources/Combine/_Introspection.swift +107 -0
- package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
- package/Sources/Compression/Compression.swift +365 -0
- package/Sources/Compression/Deflate.swift +407 -0
- package/Sources/Compression/Zlib.swift +179 -0
- package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
- package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
- package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
- package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
- package/Sources/CoreImage/CIColor.swift +41 -0
- package/Sources/CoreImage/CIContext.swift +31 -0
- package/Sources/CoreImage/CIDetector.swift +57 -0
- package/Sources/CoreImage/CIFilter.swift +243 -0
- package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
- package/Sources/CoreImage/CIImage.swift +162 -0
- package/Sources/CoreImage/QRCode.swift +393 -0
- package/Sources/CoreLocation/Coordinate.swift +30 -0
- package/Sources/CoreLocation/Location.swift +65 -0
- package/Sources/CoreML/Evaluation.swift +414 -0
- package/Sources/CoreML/FeatureValue.swift +266 -0
- package/Sources/CoreML/Model.swift +269 -0
- package/Sources/CoreML/MultiArray.swift +92 -0
- package/Sources/CoreML/Specification.swift +233 -0
- package/Sources/CoreText/CoreText.swift +64 -0
- package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
- package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
- package/Sources/CryptoKit/CryptoKit.swift +375 -0
- package/Sources/CryptoKit/Curve25519.swift +317 -0
- package/Sources/CryptoKit/P256.swift +321 -0
- package/Sources/FoundationBridge/AppStorage.swift +165 -0
- package/Sources/FoundationBridge/AssetResources.swift +90 -0
- package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
- package/Sources/FoundationBridge/AsyncImage.swift +116 -0
- package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
- package/Sources/FoundationBridge/Bundle.swift +119 -0
- package/Sources/FoundationBridge/CombineExports.swift +8 -0
- package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
- package/Sources/FoundationBridge/Dispatch.swift +458 -0
- package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
- package/Sources/FoundationBridge/FileImporter.swift +128 -0
- package/Sources/FoundationBridge/FileSystem.swift +68 -0
- package/Sources/FoundationBridge/FoundationBridge.swift +29 -0
- package/Sources/FoundationBridge/HostResolution.swift +31 -0
- package/Sources/FoundationBridge/ItemProvider.swift +655 -0
- package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
- package/Sources/FoundationBridge/Links.swift +127 -0
- package/Sources/FoundationBridge/ListFormatter.swift +32 -0
- package/Sources/FoundationBridge/Locale.swift +86 -0
- package/Sources/FoundationBridge/Localization.swift +149 -0
- package/Sources/FoundationBridge/Locks.swift +50 -0
- package/Sources/FoundationBridge/Markdown.swift +527 -0
- package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
- package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
- package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
- package/Sources/FoundationBridge/Operation.swift +195 -0
- package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
- package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
- package/Sources/FoundationBridge/SceneStorage.swift +78 -0
- package/Sources/FoundationBridge/SecurityExports.swift +8 -0
- package/Sources/FoundationBridge/Selector.swift +226 -0
- package/Sources/FoundationBridge/StringComparators.swift +17 -0
- package/Sources/FoundationBridge/Table.swift +211 -0
- package/Sources/FoundationBridge/TextAttributes.swift +42 -0
- package/Sources/FoundationBridge/Timer.swift +53 -0
- package/Sources/FoundationBridge/UITextChecker.swift +30 -0
- package/Sources/FoundationBridge/URLSession.swift +718 -0
- package/Sources/FoundationBridge/UserDefaults.swift +183 -0
- package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
- package/Sources/FoundationBridge/WebSocket.swift +187 -0
- package/Sources/FoundationModels/FoundationModels.swift +1098 -0
- package/Sources/ImageIO/GIF.swift +72 -0
- package/Sources/ImageIO/ImageIO.swift +248 -0
- package/Sources/ImageIO/ImageTypes.swift +28 -0
- package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
- package/Sources/LocalAuthentication/LAContext.swift +86 -0
- package/Sources/MapKit/Geometry.swift +223 -0
- package/Sources/MapKit/Map.swift +638 -0
- package/Sources/MapKit/MapView.swift +229 -0
- package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
- package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
- package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
- package/Sources/OSLog/OSLog.swift +6 -0
- package/Sources/Photos/Photos.swift +572 -0
- package/Sources/PhotosUI/PhotosPicker.swift +248 -0
- package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
- package/Sources/QuickLook/QuickLook.swift +168 -0
- package/Sources/SafariServices/SafariServices.swift +106 -0
- package/Sources/Security/Security.swift +332 -0
- package/Sources/StoreKit/AppStore.swift +207 -0
- package/Sources/StoreKit/Products.swift +280 -0
- package/Sources/StoreKit/RequestReview.swift +28 -0
- package/Sources/StoreKit/StoreKit1.swift +486 -0
- package/Sources/StoreKit/StoreViews.swift +428 -0
- package/Sources/StoreKit/Transactions.swift +197 -0
- package/Sources/SwiftData/Macros.swift +58 -0
- package/Sources/SwiftData/ModelActor.swift +38 -0
- package/Sources/SwiftData/ModelContainer.swift +129 -0
- package/Sources/SwiftData/ModelContext.swift +451 -0
- package/Sources/SwiftData/PersistentModel.swift +238 -0
- package/Sources/SwiftData/Properties.swift +261 -0
- package/Sources/SwiftData/Query.swift +256 -0
- package/Sources/SwiftData/Schema.swift +192 -0
- package/Sources/SwiftData/Store.swift +146 -0
- package/Sources/SwiftData/StringPredicates.swift +125 -0
- package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
- package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
- package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
- package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
- package/Sources/SwiftDataMacros/Plugin.swift +18 -0
- package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
- package/Sources/SwiftUI/API/Accessibility.swift +181 -0
- package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
- package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
- package/Sources/SwiftUI/API/Alert.swift +221 -0
- package/Sources/SwiftUI/API/AlignmentGuides.swift +65 -0
- package/Sources/SwiftUI/API/Animation.swift +285 -0
- package/Sources/SwiftUI/API/App.swift +87 -0
- package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
- package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
- package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
- package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
- package/Sources/SwiftUI/API/Canvas.swift +337 -0
- package/Sources/SwiftUI/API/Color.swift +237 -0
- package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
- package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
- package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
- package/Sources/SwiftUI/API/Commands.swift +106 -0
- package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
- package/Sources/SwiftUI/API/ContentShape.swift +33 -0
- package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
- package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
- package/Sources/SwiftUI/API/Controls.swift +300 -0
- package/Sources/SwiftUI/API/CustomLayout.swift +442 -0
- package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
- package/Sources/SwiftUI/API/Decorations.swift +92 -0
- package/Sources/SwiftUI/API/EditMode.swift +212 -0
- package/Sources/SwiftUI/API/Effects.swift +388 -0
- package/Sources/SwiftUI/API/Entry.swift +8 -0
- package/Sources/SwiftUI/API/Environment.swift +439 -0
- package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
- package/Sources/SwiftUI/API/Focus.swift +137 -0
- package/Sources/SwiftUI/API/Font.swift +131 -0
- package/Sources/SwiftUI/API/Gauge.swift +290 -0
- package/Sources/SwiftUI/API/Geometry.swift +89 -0
- package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
- package/Sources/SwiftUI/API/GeometryReader.swift +135 -0
- package/Sources/SwiftUI/API/GestureState.swift +65 -0
- package/Sources/SwiftUI/API/Gestures.swift +342 -0
- package/Sources/SwiftUI/API/Glass.swift +127 -0
- package/Sources/SwiftUI/API/Grid.swift +188 -0
- package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
- package/Sources/SwiftUI/API/KeyPress.swift +54 -0
- package/Sources/SwiftUI/API/LabelStyle.swift +124 -0
- package/Sources/SwiftUI/API/Layout.swift +220 -0
- package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
- package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
- package/Sources/SwiftUI/API/Lists.swift +331 -0
- package/Sources/SwiftUI/API/Menu.swift +58 -0
- package/Sources/SwiftUI/API/Modifiers.swift +313 -0
- package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
- package/Sources/SwiftUI/API/Namespace.swift +44 -0
- package/Sources/SwiftUI/API/Navigation.swift +386 -0
- package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
- package/Sources/SwiftUI/API/ObservableObject.swift +293 -0
- package/Sources/SwiftUI/API/OnChange.swift +48 -0
- package/Sources/SwiftUI/API/Path.swift +543 -0
- package/Sources/SwiftUI/API/Phase8Controls.swift +411 -0
- package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
- package/Sources/SwiftUI/API/Picker.swift +185 -0
- package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
- package/Sources/SwiftUI/API/Popover.swift +41 -0
- package/Sources/SwiftUI/API/Preferences.swift +262 -0
- package/Sources/SwiftUI/API/Presentation.swift +122 -0
- package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
- package/Sources/SwiftUI/API/Primitives.swift +517 -0
- package/Sources/SwiftUI/API/Publishers.swift +107 -0
- package/Sources/SwiftUI/API/Redaction.swift +75 -0
- package/Sources/SwiftUI/API/RowActions.swift +84 -0
- package/Sources/SwiftUI/API/Scenes.swift +131 -0
- package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
- package/Sources/SwiftUI/API/ScrollTargets.swift +104 -0
- package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
- package/Sources/SwiftUI/API/SectionSupplements.swift +96 -0
- package/Sources/SwiftUI/API/Shape.swift +214 -0
- package/Sources/SwiftUI/API/ShapeStyle.swift +409 -0
- package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
- package/Sources/SwiftUI/API/Sharing.swift +193 -0
- package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
- package/Sources/SwiftUI/API/State.swift +144 -0
- package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
- package/Sources/SwiftUI/API/StrokeStyle.swift +30 -0
- package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
- package/Sources/SwiftUI/API/TabContent.swift +841 -0
- package/Sources/SwiftUI/API/Table.swift +382 -0
- package/Sources/SwiftUI/API/Tabs.swift +263 -0
- package/Sources/SwiftUI/API/Tasks.swift +35 -0
- package/Sources/SwiftUI/API/Text.swift +386 -0
- package/Sources/SwiftUI/API/TextDates.swift +61 -0
- package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
- package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
- package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
- package/Sources/SwiftUI/API/Timeline.swift +212 -0
- package/Sources/SwiftUI/API/Toolbar.swift +251 -0
- package/Sources/SwiftUI/API/Transfer.swift +145 -0
- package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
- package/Sources/SwiftUI/API/Video.swift +64 -0
- package/Sources/SwiftUI/API/View.swift +215 -0
- package/Sources/SwiftUI/API/ViewModifier.swift +43 -0
- package/Sources/SwiftUI/API/VisualEffect.swift +155 -0
- package/Sources/SwiftUI/API/Windows.swift +25 -0
- package/Sources/SwiftUI/Charts/Axis.swift +325 -0
- package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
- package/Sources/SwiftUI/Charts/Chart.swift +660 -0
- package/Sources/SwiftUI/Charts/ChartContent.swift +376 -0
- package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
- package/Sources/SwiftUI/Charts/Marks.swift +204 -0
- package/Sources/SwiftUI/Charts/Plottable.swift +99 -0
- package/Sources/SwiftUI/Charts/Scales.swift +326 -0
- package/Sources/SwiftUI/Localization/Localization.swift +498 -0
- package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
- package/Sources/SwiftUI/Runtime/Executor.swift +85 -0
- package/Sources/SwiftUI/Runtime/Exports.swift +101 -0
- package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
- package/Sources/SwiftUI/Runtime/JSON.swift +143 -0
- package/Sources/SwiftUI/Runtime/JSONParser.swift +443 -0
- package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
- package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
- package/Sources/SwiftUI/Runtime/Ops.swift +152 -0
- package/Sources/SwiftUI/Runtime/Reconciler.swift +219 -0
- package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
- package/Sources/SwiftUI/Runtime/Runtime.swift +2146 -0
- package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
- package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
- package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
- package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
- package/Sources/Symbols/Symbols.swift +25 -0
- package/Sources/Translation/Translation.swift +423 -0
- package/Sources/UIKit/Activity.swift +213 -0
- package/Sources/UIKit/Alerts.swift +69 -0
- package/Sources/UIKit/AppDelegate.swift +222 -0
- package/Sources/UIKit/Appearance.swift +84 -0
- package/Sources/UIKit/ColorConversions.swift +70 -0
- package/Sources/UIKit/Controls.swift +225 -0
- package/Sources/UIKit/Device.swift +200 -0
- package/Sources/UIKit/Feedback.swift +65 -0
- package/Sources/UIKit/Font.swift +307 -0
- package/Sources/UIKit/Graphics.swift +204 -0
- package/Sources/UIKit/HostingController.swift +185 -0
- package/Sources/UIKit/Identity.swift +24 -0
- package/Sources/UIKit/Introspectable.swift +510 -0
- package/Sources/UIKit/Pasteboard.swift +363 -0
- package/Sources/UIKit/PhotoAlbum.swift +81 -0
- package/Sources/UIKit/RemoteNotifications.swift +15 -0
- package/Sources/UIKit/Representable.swift +288 -0
- package/Sources/UIKit/SafeArea.swift +12 -0
- package/Sources/UIKit/SceneDelegates.swift +132 -0
- package/Sources/UIKit/Scenes.swift +40 -0
- package/Sources/UIKit/ScrollView.swift +157 -0
- package/Sources/UIKit/ShortcutItems.swift +67 -0
- package/Sources/UIKit/SymbolConfiguration.swift +124 -0
- package/Sources/UIKit/TargetAction.swift +123 -0
- package/Sources/UIKit/TextPaste.swift +161 -0
- package/Sources/UIKit/TextView.swift +538 -0
- package/Sources/UIKit/UIKit.swift +292 -0
- package/Sources/UIKit/UIView.swift +855 -0
- package/Sources/UIKit/ViewTranslation.swift +311 -0
- package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
- package/Sources/UserNotifications/Content.swift +370 -0
- package/Sources/UserNotifications/NotificationCenter.swift +309 -0
- package/Sources/WeatherKit/WeatherKit.swift +228 -0
- package/Sources/WebKit/WebKit.swift +245 -0
- package/Sources/os/os.swift +376 -0
- package/Sources/zlib/zlib.swift +6 -0
- package/index.d.ts +2 -0
- package/index.mjs +16 -0
- package/manifest.d.mts +2 -0
- package/manifest.mjs +39 -0
- package/package.json +30 -4
- package/sync-sources.mjs +33 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
// Translation (iOS 17.4 / 18): Apple's on-device translation, over the
|
|
2
|
+
// browser's own translator where the page has one. Chrome (138 and later,
|
|
3
|
+
// on desktop) has a built-in `Translator` API that translates on the device
|
|
4
|
+
// with models it downloads per language pair, and a `LanguageDetector`; the
|
|
5
|
+
// page uses them for `translate` host requests (Web/src/translation.ts). A
|
|
6
|
+
// browser without them, and headless runs, answer that no pair is supported,
|
|
7
|
+
// so `LanguageAvailability` reports `.unsupported` and a session's
|
|
8
|
+
// translations fail with `TranslationError.unsupportedLanguagePairing`, as on
|
|
9
|
+
// a device without the pair. Apps that fall back to a server (Ice Cubes
|
|
10
|
+
// translates with the instance or DeepL) then take that path.
|
|
11
|
+
//
|
|
12
|
+
// Exchanges, as host requests of kind `translate`:
|
|
13
|
+
//
|
|
14
|
+
// { "action": "availability", "source": "en" | null, "target": "fr", "text"?: "…" }
|
|
15
|
+
// → { "status": "installed" | "supported" | "unsupported" }
|
|
16
|
+
// { "action": "translate", "source": "en" | null, "target": "fr",
|
|
17
|
+
// "texts": ["…"], "allowDownload": true }
|
|
18
|
+
// → { "source": "en", "texts": ["…"] }, or { "status": "unsupported" }
|
|
19
|
+
//
|
|
20
|
+
// Languages travel as BCP 47 language tags ("en", "pt", "zh-Hant").
|
|
21
|
+
|
|
22
|
+
import Foundation
|
|
23
|
+
import FoundationBridge
|
|
24
|
+
import SwiftUI
|
|
25
|
+
|
|
26
|
+
// MARK: - Errors
|
|
27
|
+
|
|
28
|
+
/// Why a translation failed. Compare with `~=` (`catch TranslationError.unsupportedLanguagePairing`).
|
|
29
|
+
public struct TranslationError: Error, LocalizedError, Hashable, Sendable, CustomStringConvertible {
|
|
30
|
+
enum Code: String, Sendable { case unsupportedSourceLanguage, unsupportedTargetLanguage, unsupportedLanguagePairing,
|
|
31
|
+
unableToIdentifyLanguage, nothingToTranslate, internalError, notInstalled }
|
|
32
|
+
let code: Code
|
|
33
|
+
|
|
34
|
+
/// The source language is one the translator does not have.
|
|
35
|
+
public static let unsupportedSourceLanguage = TranslationError(code: .unsupportedSourceLanguage)
|
|
36
|
+
/// The target language is one the translator does not have.
|
|
37
|
+
public static let unsupportedTargetLanguage = TranslationError(code: .unsupportedTargetLanguage)
|
|
38
|
+
/// The translator cannot translate between the two languages: always so
|
|
39
|
+
/// in a browser without a built-in translator.
|
|
40
|
+
public static let unsupportedLanguagePairing = TranslationError(code: .unsupportedLanguagePairing)
|
|
41
|
+
/// The source language was not given and could not be detected.
|
|
42
|
+
public static let unableToIdentifyLanguage = TranslationError(code: .unableToIdentifyLanguage)
|
|
43
|
+
/// The text was empty.
|
|
44
|
+
public static let nothingToTranslate = TranslationError(code: .nothingToTranslate)
|
|
45
|
+
/// The translator failed.
|
|
46
|
+
public static let internalError = TranslationError(code: .internalError)
|
|
47
|
+
/// The pair's model is not downloaded and the session may not download it.
|
|
48
|
+
public static let notInstalled = TranslationError(code: .notInstalled)
|
|
49
|
+
|
|
50
|
+
public static func ~= (lhs: TranslationError, rhs: any Error) -> Bool {
|
|
51
|
+
(rhs as? TranslationError) == lhs
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public var description: String { "TranslationError.\(code.rawValue)" }
|
|
55
|
+
|
|
56
|
+
public var errorDescription: String? {
|
|
57
|
+
switch code {
|
|
58
|
+
case .unsupportedSourceLanguage: "The source language is not supported."
|
|
59
|
+
case .unsupportedTargetLanguage: "The target language is not supported."
|
|
60
|
+
case .unsupportedLanguagePairing: "Translation between these languages is not supported."
|
|
61
|
+
case .unableToIdentifyLanguage: "The language of the text could not be identified."
|
|
62
|
+
case .nothingToTranslate: "There is nothing to translate."
|
|
63
|
+
case .internalError: "The translation failed."
|
|
64
|
+
case .notInstalled: "The languages for this translation are not downloaded."
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// MARK: - The page
|
|
70
|
+
|
|
71
|
+
/// How the module reaches the page; tests replace `transport`.
|
|
72
|
+
enum _TranslationHost {
|
|
73
|
+
/// Performs one `translate` request.
|
|
74
|
+
nonisolated(unsafe) static var transport: @Sendable (_JSON) async throws -> _JSON = { params in
|
|
75
|
+
try await _Runtime.shared._hostRequest(kind: "translate", params: params,
|
|
76
|
+
headless: .object(["status": .string("unsupported")]))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// A language's BCP 47 tag for the page: its language code, with the
|
|
80
|
+
/// script for traditional Chinese ("zh-Hant"), which translators treat as a
|
|
81
|
+
/// language of its own.
|
|
82
|
+
static func tag(_ language: Locale.Language) -> String {
|
|
83
|
+
let code = language.languageCode?.identifier ?? language.minimalIdentifier
|
|
84
|
+
if code == "zh" {
|
|
85
|
+
let script = language.script?.identifier
|
|
86
|
+
let region = language.region?.identifier
|
|
87
|
+
if script == "Hant" || (script == nil && ["TW", "HK", "MO"].contains(region ?? "")) { return "zh-Hant" }
|
|
88
|
+
}
|
|
89
|
+
return code
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// The language translations go to when a session names none: the viewer's first preferred language.
|
|
93
|
+
static var defaultTarget: Locale.Language {
|
|
94
|
+
Locale.Language(identifier: Locale.preferredLanguages.first ?? Locale.current.identifier)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static func status(_ value: _JSON) -> LanguageAvailability.Status {
|
|
98
|
+
guard case .object(let fields) = value, case .string(let status)? = fields["status"] else { return .unsupported }
|
|
99
|
+
switch status {
|
|
100
|
+
case "installed": return .installed
|
|
101
|
+
case "supported": return .supported
|
|
102
|
+
default: return .unsupported
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// The error a refused request stands for: the page's message starts with a tag.
|
|
107
|
+
static func error(_ error: any Error) -> TranslationError {
|
|
108
|
+
if let error = error as? TranslationError { return error }
|
|
109
|
+
let message = (error as? _HostRequestError)?.message ?? ""
|
|
110
|
+
if message.hasPrefix("unsupported") { return .unsupportedLanguagePairing }
|
|
111
|
+
if message.hasPrefix("unidentified") { return .unableToIdentifyLanguage }
|
|
112
|
+
if message.hasPrefix("download") { return .notInstalled }
|
|
113
|
+
return .internalError
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// MARK: - Availability
|
|
118
|
+
|
|
119
|
+
/// Which languages can be translated, as the page's translator reports.
|
|
120
|
+
public final class LanguageAvailability: Sendable {
|
|
121
|
+
/// Whether a pair can be translated.
|
|
122
|
+
public enum Status: Sendable, Hashable {
|
|
123
|
+
/// The pair's model is on the device: translations start at once.
|
|
124
|
+
case installed
|
|
125
|
+
/// The pair is supported; its model is downloaded first.
|
|
126
|
+
case supported
|
|
127
|
+
/// The pair cannot be translated (always so without a built-in translator).
|
|
128
|
+
case unsupported
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public init() {}
|
|
132
|
+
|
|
133
|
+
/// The languages Apple's translator offers. In a browser without a
|
|
134
|
+
/// translator the list is the same: availability is answered per pair.
|
|
135
|
+
public var supportedLanguages: [Locale.Language] {
|
|
136
|
+
get async {
|
|
137
|
+
["ar", "zh-Hans", "zh-Hant", "nl", "en-US", "en-GB", "fr", "de", "hi", "id", "it", "ja", "ko", "pl",
|
|
138
|
+
"pt-BR", "ru", "es", "th", "tr", "uk", "vi"].map { Locale.Language(identifier: $0) }
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// Whether `source` can be translated to `target` (the viewer's language when nil).
|
|
143
|
+
public func status(from source: Locale.Language, to target: Locale.Language?) async throws -> Status {
|
|
144
|
+
try await Self.ask(source: source, target: target, text: nil)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// Whether `text`, whose language the page detects, can be translated to
|
|
148
|
+
/// `target`. Fails with `unableToIdentifyLanguage` when it cannot tell.
|
|
149
|
+
public func status(for text: String, to target: Locale.Language?) async throws -> Status {
|
|
150
|
+
try await Self.ask(source: nil, target: target, text: text)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static func ask(source: Locale.Language?, target: Locale.Language?, text: String?) async throws -> Status {
|
|
154
|
+
var params: [String: _JSON] = [
|
|
155
|
+
"action": .string("availability"),
|
|
156
|
+
"source": source.map { .string(_TranslationHost.tag($0)) } ?? .null,
|
|
157
|
+
"target": .string(_TranslationHost.tag(target ?? _TranslationHost.defaultTarget)),
|
|
158
|
+
]
|
|
159
|
+
if let text { params["text"] = .string(text) }
|
|
160
|
+
do {
|
|
161
|
+
return _TranslationHost.status(try await _TranslationHost.transport(.object(params)))
|
|
162
|
+
} catch {
|
|
163
|
+
let error = _TranslationHost.error(error)
|
|
164
|
+
if error == .unableToIdentifyLanguage { throw error }
|
|
165
|
+
return .unsupported
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// MARK: - Sessions
|
|
171
|
+
|
|
172
|
+
/// Translates text between two languages. SwiftUI hands one to the action of
|
|
173
|
+
/// `.translationTask`; iOS 26's `init(installedSource:target:)` makes one
|
|
174
|
+
/// directly, which never downloads a model.
|
|
175
|
+
public final class TranslationSession: @unchecked Sendable {
|
|
176
|
+
/// A text to translate in a batch, with an identifier to match its response.
|
|
177
|
+
public struct Request: Sendable, Hashable {
|
|
178
|
+
public var sourceText: String
|
|
179
|
+
public var clientIdentifier: String?
|
|
180
|
+
|
|
181
|
+
public init(sourceText: String, clientIdentifier: String? = nil) {
|
|
182
|
+
self.sourceText = sourceText
|
|
183
|
+
self.clientIdentifier = clientIdentifier
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/// A translated text.
|
|
188
|
+
public struct Response: Sendable, Hashable {
|
|
189
|
+
public var sourceLanguage: Locale.Language
|
|
190
|
+
public var targetLanguage: Locale.Language
|
|
191
|
+
public var sourceText: String
|
|
192
|
+
public var targetText: String
|
|
193
|
+
public var clientIdentifier: String?
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/// The languages of a `.translationTask`: nil source means detected, nil
|
|
197
|
+
/// target the viewer's language. `invalidate()` makes the task run again
|
|
198
|
+
/// with the same languages.
|
|
199
|
+
public struct Configuration: Sendable, Hashable {
|
|
200
|
+
public var source: Locale.Language?
|
|
201
|
+
public var target: Locale.Language?
|
|
202
|
+
public private(set) var version = 0
|
|
203
|
+
|
|
204
|
+
public init(source: Locale.Language? = nil, target: Locale.Language? = nil) {
|
|
205
|
+
self.source = source
|
|
206
|
+
self.target = target
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/// Runs the configuration's translation task again.
|
|
210
|
+
public mutating func invalidate() { version += 1 }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// The responses of `translate(batch:)`, in the order of the requests.
|
|
214
|
+
public struct BatchResponse: AsyncSequence, Sendable {
|
|
215
|
+
public typealias Element = Response
|
|
216
|
+
let responses: @Sendable () async throws -> [Response]
|
|
217
|
+
|
|
218
|
+
public struct AsyncIterator: AsyncIteratorProtocol {
|
|
219
|
+
let load: @Sendable () async throws -> [Response]
|
|
220
|
+
var loaded: [Response]?
|
|
221
|
+
var index = 0
|
|
222
|
+
|
|
223
|
+
public mutating func next() async throws -> Response? {
|
|
224
|
+
if loaded == nil { loaded = try await load() }
|
|
225
|
+
guard let loaded, index < loaded.count else { return nil }
|
|
226
|
+
defer { index += 1 }
|
|
227
|
+
return loaded[index]
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
public func makeAsyncIterator() -> AsyncIterator { AsyncIterator(load: responses) }
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/// The language translated from; nil when each text's language is detected.
|
|
235
|
+
public let sourceLanguage: Locale.Language?
|
|
236
|
+
/// The language translated to; nil for the viewer's language.
|
|
237
|
+
public let targetLanguage: Locale.Language?
|
|
238
|
+
/// Whether the session may download a pair's model (the page asks the
|
|
239
|
+
/// browser to, which Chrome allows within a tap).
|
|
240
|
+
public let canRequestDownloads: Bool
|
|
241
|
+
private var cancelled = false
|
|
242
|
+
|
|
243
|
+
init(source: Locale.Language?, target: Locale.Language?, canRequestDownloads: Bool) {
|
|
244
|
+
sourceLanguage = source
|
|
245
|
+
targetLanguage = target
|
|
246
|
+
self.canRequestDownloads = canRequestDownloads
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/// A session for a pair whose model is already on the device: it never
|
|
250
|
+
/// downloads one, and fails with `notInstalled` when it would have to.
|
|
251
|
+
public convenience init(installedSource: Locale.Language, target: Locale.Language? = nil) {
|
|
252
|
+
self.init(source: installedSource, target: target, canRequestDownloads: false)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/// Whether the pair's model is on the device.
|
|
256
|
+
public var isReady: Bool {
|
|
257
|
+
get async {
|
|
258
|
+
guard let sourceLanguage else { return false }
|
|
259
|
+
return (try? await LanguageAvailability().status(from: sourceLanguage, to: targetLanguage)) == .installed
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/// Downloads the pair's model ahead of the first translation, when it is
|
|
264
|
+
/// supported and not yet installed.
|
|
265
|
+
public func prepareTranslation() async throws {
|
|
266
|
+
guard let sourceLanguage else { return }
|
|
267
|
+
switch try await LanguageAvailability().status(from: sourceLanguage, to: targetLanguage) {
|
|
268
|
+
case .installed: return
|
|
269
|
+
case .unsupported: throw TranslationError.unsupportedLanguagePairing
|
|
270
|
+
case .supported:
|
|
271
|
+
guard canRequestDownloads else { throw TranslationError.notInstalled }
|
|
272
|
+
_ = try await translate(texts: [""])
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/// Translates one text.
|
|
277
|
+
public func translate(_ string: String) async throws -> Response {
|
|
278
|
+
guard !string.isEmpty else { throw TranslationError.nothingToTranslate }
|
|
279
|
+
return try await translations(from: [Request(sourceText: string)])[0]
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/// Translates the requests together, answering in their order.
|
|
283
|
+
public func translations(from batch: [Request]) async throws -> [Response] {
|
|
284
|
+
guard !batch.isEmpty else { return [] }
|
|
285
|
+
let (source, texts) = try await translate(texts: batch.map(\.sourceText))
|
|
286
|
+
let target = targetLanguage ?? _TranslationHost.defaultTarget
|
|
287
|
+
return zip(batch, texts).map { request, text in
|
|
288
|
+
Response(sourceLanguage: source, targetLanguage: target, sourceText: request.sourceText,
|
|
289
|
+
targetText: text, clientIdentifier: request.clientIdentifier)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/// Translates the requests, delivering each response as a sequence.
|
|
294
|
+
public func translate(batch: [Request]) -> BatchResponse {
|
|
295
|
+
BatchResponse { [self] in try await translations(from: batch) }
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// Stops the session: later translations fail.
|
|
299
|
+
public func cancel() { cancelled = true }
|
|
300
|
+
|
|
301
|
+
private func translate(texts: [String]) async throws -> (Locale.Language, [String]) {
|
|
302
|
+
if cancelled || Task.isCancelled { throw CancellationError() }
|
|
303
|
+
let params: _JSON = .object([
|
|
304
|
+
"action": .string("translate"),
|
|
305
|
+
"source": sourceLanguage.map { .string(_TranslationHost.tag($0)) } ?? .null,
|
|
306
|
+
"target": .string(_TranslationHost.tag(targetLanguage ?? _TranslationHost.defaultTarget)),
|
|
307
|
+
"texts": .array(texts.map { .string($0) }),
|
|
308
|
+
"allowDownload": .bool(canRequestDownloads),
|
|
309
|
+
])
|
|
310
|
+
let value: _JSON
|
|
311
|
+
do {
|
|
312
|
+
value = try await _TranslationHost.transport(params)
|
|
313
|
+
} catch {
|
|
314
|
+
throw _TranslationHost.error(error)
|
|
315
|
+
}
|
|
316
|
+
guard case .object(let fields) = value, case .array(let items)? = fields["texts"] else {
|
|
317
|
+
throw _TranslationHost.status(value) == .unsupported ? TranslationError.unsupportedLanguagePairing
|
|
318
|
+
: TranslationError.internalError
|
|
319
|
+
}
|
|
320
|
+
let translated = items.map { item -> String in
|
|
321
|
+
if case .string(let text) = item { return text }
|
|
322
|
+
return ""
|
|
323
|
+
}
|
|
324
|
+
guard translated.count == texts.count else { throw TranslationError.internalError }
|
|
325
|
+
var source = sourceLanguage
|
|
326
|
+
if source == nil, case .string(let detected)? = fields["source"] { source = Locale.Language(identifier: detected) }
|
|
327
|
+
guard let source else { throw TranslationError.unableToIdentifyLanguage }
|
|
328
|
+
return (source, translated)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// MARK: - SwiftUI
|
|
333
|
+
|
|
334
|
+
nonisolated extension View {
|
|
335
|
+
/// Runs `action` with a session for `configuration` when the view appears
|
|
336
|
+
/// with one, and again each time it changes (`invalidate()` included). A
|
|
337
|
+
/// nil configuration runs nothing. The session may download a model.
|
|
338
|
+
public func translationTask(_ configuration: TranslationSession.Configuration?,
|
|
339
|
+
@_inheritActorContext action: @escaping @Sendable (TranslationSession) async -> Void) -> some View {
|
|
340
|
+
task(id: configuration) {
|
|
341
|
+
guard let configuration else { return }
|
|
342
|
+
await action(TranslationSession(source: configuration.source, target: configuration.target,
|
|
343
|
+
canRequestDownloads: true))
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/// Runs `action` with a session from `source` to `target` when the view appears.
|
|
348
|
+
public func translationTask(source: Locale.Language? = nil, target: Locale.Language? = nil,
|
|
349
|
+
@_inheritActorContext action: @escaping @Sendable (TranslationSession) async -> Void) -> some View {
|
|
350
|
+
task {
|
|
351
|
+
await action(TranslationSession(source: source, target: target, canRequestDownloads: true))
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/// The system translation overlay for `text`. On an iPhone it is a sheet;
|
|
356
|
+
/// here too: the original, its translation into the viewer's language
|
|
357
|
+
/// (or why there is none), a Done button and, with `replacementAction`,
|
|
358
|
+
/// "Replace with Translation". The popover's anchor and arrow edge are ignored.
|
|
359
|
+
@MainActor
|
|
360
|
+
public func translationPresentation(isPresented: Binding<Bool>, text: String,
|
|
361
|
+
attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds),
|
|
362
|
+
arrowEdge: Edge = .top,
|
|
363
|
+
replacementAction: ((String) -> Void)? = nil) -> some View {
|
|
364
|
+
sheet(isPresented: isPresented) {
|
|
365
|
+
_TranslationPresentation(text: text, replacementAction: replacementAction)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/// The sheet of `.translationPresentation`.
|
|
371
|
+
struct _TranslationPresentation: View {
|
|
372
|
+
let text: String
|
|
373
|
+
let replacementAction: ((String) -> Void)?
|
|
374
|
+
@Environment(\.dismiss) private var dismiss
|
|
375
|
+
@State private var translation: String?
|
|
376
|
+
@State private var failure: TranslationError?
|
|
377
|
+
|
|
378
|
+
var body: some View {
|
|
379
|
+
NavigationStack {
|
|
380
|
+
List {
|
|
381
|
+
Section {
|
|
382
|
+
Text(text)
|
|
383
|
+
}
|
|
384
|
+
Section {
|
|
385
|
+
if let translation {
|
|
386
|
+
Text(translation)
|
|
387
|
+
} else if let failure {
|
|
388
|
+
Text(failure == .unsupportedLanguagePairing || failure == .unableToIdentifyLanguage
|
|
389
|
+
? "Translation is not available in this browser for this text."
|
|
390
|
+
: failure.errorDescription ?? "The translation failed.")
|
|
391
|
+
.foregroundStyle(.secondary)
|
|
392
|
+
} else {
|
|
393
|
+
ProgressView()
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if let translation, let replacementAction {
|
|
397
|
+
Section {
|
|
398
|
+
Button("Replace with Translation") {
|
|
399
|
+
replacementAction(translation)
|
|
400
|
+
dismiss()
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
.navigationTitle("Translate")
|
|
406
|
+
.navigationBarTitleDisplayMode(.inline)
|
|
407
|
+
.toolbar {
|
|
408
|
+
ToolbarItem(placement: .confirmationAction) {
|
|
409
|
+
Button("Done") { dismiss() }
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
.translationTask(source: nil, target: nil) { session in
|
|
414
|
+
do {
|
|
415
|
+
let response = try await session.translate(text)
|
|
416
|
+
await MainActor.run { translation = response.targetText }
|
|
417
|
+
} catch {
|
|
418
|
+
let failure = error as? TranslationError ?? .internalError
|
|
419
|
+
await MainActor.run { self.failure = failure }
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// UIKit's share sheet in the browser. Presenting a `UIActivityViewController`
|
|
2
|
+
// (any controller's `present`, or a `UIViewControllerRepresentable` that
|
|
3
|
+
// shows one in a sheet) shares its items through the page, as SwiftUI's
|
|
4
|
+
// `ShareLink` does: a `share` host request, which the page performs with the
|
|
5
|
+
// Web Share API, or as downloads where the browser has none
|
|
6
|
+
// (docs/ops-protocol.md, "Sharing"). Strings become the text, the first URL
|
|
7
|
+
// the link, images their files; an item source gives its item for no
|
|
8
|
+
// particular activity, and its link metadata's title becomes the share's
|
|
9
|
+
// title. The controller is done once the page answers: it dismisses itself
|
|
10
|
+
// and reports to `completionWithItemsHandler` (shared or not, with no
|
|
11
|
+
// activity type, since the browser does not say where the items went).
|
|
12
|
+
// Custom `UIActivity`s are kept; the browser's sheet cannot show them.
|
|
13
|
+
|
|
14
|
+
import Foundation
|
|
15
|
+
import FoundationBridge
|
|
16
|
+
import SwiftUI
|
|
17
|
+
|
|
18
|
+
// MARK: - Activities
|
|
19
|
+
|
|
20
|
+
/// A service the share sheet offers. Kept: the browser's share sheet lists
|
|
21
|
+
/// its own targets, so an app's activities are never shown or performed.
|
|
22
|
+
open class UIActivity: @unchecked Sendable {
|
|
23
|
+
public struct ActivityType: RawRepresentable, Hashable, Sendable {
|
|
24
|
+
public let rawValue: String
|
|
25
|
+
public init(rawValue: String) { self.rawValue = rawValue }
|
|
26
|
+
public init(_ rawValue: String) { self.rawValue = rawValue }
|
|
27
|
+
|
|
28
|
+
public static let postToFacebook = ActivityType("com.apple.UIKit.activity.PostToFacebook")
|
|
29
|
+
public static let postToTwitter = ActivityType("com.apple.UIKit.activity.PostToTwitter")
|
|
30
|
+
public static let postToWeibo = ActivityType("com.apple.UIKit.activity.PostToWeibo")
|
|
31
|
+
public static let message = ActivityType("com.apple.UIKit.activity.Message")
|
|
32
|
+
public static let mail = ActivityType("com.apple.UIKit.activity.Mail")
|
|
33
|
+
public static let print = ActivityType("com.apple.UIKit.activity.Print")
|
|
34
|
+
public static let copyToPasteboard = ActivityType("com.apple.UIKit.activity.CopyToPasteboard")
|
|
35
|
+
public static let assignToContact = ActivityType("com.apple.UIKit.activity.AssignToContact")
|
|
36
|
+
public static let saveToCameraRoll = ActivityType("com.apple.UIKit.activity.SaveToCameraRoll")
|
|
37
|
+
public static let addToReadingList = ActivityType("com.apple.UIKit.activity.AddToReadingList")
|
|
38
|
+
public static let postToFlickr = ActivityType("com.apple.UIKit.activity.PostToFlickr")
|
|
39
|
+
public static let postToVimeo = ActivityType("com.apple.UIKit.activity.PostToVimeo")
|
|
40
|
+
public static let postToTencentWeibo = ActivityType("com.apple.UIKit.activity.TencentWeibo")
|
|
41
|
+
public static let airDrop = ActivityType("com.apple.UIKit.activity.AirDrop")
|
|
42
|
+
public static let openInIBooks = ActivityType("com.apple.UIKit.activity.OpenInIBooks")
|
|
43
|
+
public static let markupAsPDF = ActivityType("com.apple.UIKit.activity.MarkupAsPDF")
|
|
44
|
+
public static let sharePlay = ActivityType("com.apple.UIKit.activity.SharePlay")
|
|
45
|
+
public static let collaborationInviteWithLink = ActivityType("com.apple.UIKit.activity.CollaborationInviteWithLink")
|
|
46
|
+
public static let collaborationCopyLink = ActivityType("com.apple.UIKit.activity.CollaborationCopyLink")
|
|
47
|
+
public static let addToHomeScreen = ActivityType("com.apple.UIKit.activity.AddToHomeScreen")
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public enum Category: Int, Sendable { case action, share }
|
|
51
|
+
|
|
52
|
+
public init() {}
|
|
53
|
+
|
|
54
|
+
open class var activityCategory: Category { .action }
|
|
55
|
+
open var activityType: ActivityType? { nil }
|
|
56
|
+
open var activityTitle: String? { nil }
|
|
57
|
+
open var activityImage: UIImage? { nil }
|
|
58
|
+
open var activityViewController: UIViewController? { nil }
|
|
59
|
+
open func canPerform(withActivityItems activityItems: [Any]) -> Bool { false }
|
|
60
|
+
open func prepare(withActivityItems activityItems: [Any]) {}
|
|
61
|
+
open func perform() { activityDidFinish(false) }
|
|
62
|
+
open func activityDidFinish(_ completed: Bool) {}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// An object that gives the share sheet an item on demand. On iOS the
|
|
66
|
+
/// methods after the first two are optional; here they have defaults.
|
|
67
|
+
@MainActor
|
|
68
|
+
public protocol UIActivityItemSource: AnyObject {
|
|
69
|
+
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any
|
|
70
|
+
func activityViewController(_ activityViewController: UIActivityViewController,
|
|
71
|
+
itemForActivityType activityType: UIActivity.ActivityType?) -> Any?
|
|
72
|
+
func activityViewController(_ activityViewController: UIActivityViewController,
|
|
73
|
+
subjectForActivityType activityType: UIActivity.ActivityType?) -> String
|
|
74
|
+
func activityViewController(_ activityViewController: UIActivityViewController,
|
|
75
|
+
dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?) -> String
|
|
76
|
+
func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata?
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
extension UIActivityItemSource {
|
|
80
|
+
public func activityViewController(_ activityViewController: UIActivityViewController,
|
|
81
|
+
subjectForActivityType activityType: UIActivity.ActivityType?) -> String { "" }
|
|
82
|
+
public func activityViewController(_ activityViewController: UIActivityViewController,
|
|
83
|
+
dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?) -> String { "" }
|
|
84
|
+
public func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? { nil }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// An item source that makes its item when asked (an `Operation` on iOS):
|
|
88
|
+
/// the share sheet takes `item`, which defaults to the placeholder.
|
|
89
|
+
@MainActor
|
|
90
|
+
open class UIActivityItemProvider: UIActivityItemSource {
|
|
91
|
+
public let placeholderItem: Any?
|
|
92
|
+
public private(set) var activityType: UIActivity.ActivityType?
|
|
93
|
+
|
|
94
|
+
public init(placeholderItem: Any) { self.placeholderItem = placeholderItem }
|
|
95
|
+
|
|
96
|
+
open var item: Any { placeholderItem as Any }
|
|
97
|
+
|
|
98
|
+
public func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { placeholderItem as Any }
|
|
99
|
+
public func activityViewController(_ activityViewController: UIActivityViewController,
|
|
100
|
+
itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
|
|
101
|
+
self.activityType = activityType
|
|
102
|
+
return item
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// A link's title, address and pictures, for a share sheet's header or a
|
|
107
|
+
/// link preview. LinkPresentation re-exports it (Sources/LinkPresentation);
|
|
108
|
+
/// it lives here so that `UIActivityItemSource` can name it, as on iOS.
|
|
109
|
+
open class LPLinkMetadata: NSObject, @unchecked Sendable {
|
|
110
|
+
/// The URL the metadata was asked for.
|
|
111
|
+
open var originalURL: URL?
|
|
112
|
+
/// The URL the metadata describes (after redirects).
|
|
113
|
+
open var url: URL?
|
|
114
|
+
open var title: String?
|
|
115
|
+
open var iconProvider: NSItemProvider?
|
|
116
|
+
open var imageProvider: NSItemProvider?
|
|
117
|
+
open var videoProvider: NSItemProvider?
|
|
118
|
+
open var remoteVideoURL: URL?
|
|
119
|
+
|
|
120
|
+
public override init() { super.init() }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// MARK: - The share sheet
|
|
124
|
+
|
|
125
|
+
/// The share sheet: presenting it shares its items through the page (see
|
|
126
|
+
/// the top of this file).
|
|
127
|
+
@MainActor
|
|
128
|
+
open class UIActivityViewController: UIViewController {
|
|
129
|
+
public typealias CompletionWithItemsHandler = (UIActivity.ActivityType?, Bool, [Any]?, (any Error)?) -> Void
|
|
130
|
+
|
|
131
|
+
/// Shares a request through the page; tests replace it.
|
|
132
|
+
static var shareOnPage: @MainActor (_JSON) async -> Bool = { params in
|
|
133
|
+
guard let answer = try? await _Runtime.shared._hostRequest(kind: "share", params: params) else { return false }
|
|
134
|
+
if case .object(let fields) = answer, case .string(let outcome)? = fields["outcome"] { return outcome != "cancelled" }
|
|
135
|
+
return true
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public let activityItems: [Any]
|
|
139
|
+
public let applicationActivities: [UIActivity]?
|
|
140
|
+
open var excludedActivityTypes: [UIActivity.ActivityType]?
|
|
141
|
+
open var completionWithItemsHandler: CompletionWithItemsHandler?
|
|
142
|
+
open var allowsProminentActivity = true
|
|
143
|
+
private var shared = false
|
|
144
|
+
|
|
145
|
+
public init(activityItems: [Any], applicationActivities: [UIActivity]?) {
|
|
146
|
+
self.activityItems = activityItems
|
|
147
|
+
self.applicationActivities = applicationActivities
|
|
148
|
+
super.init(nibName: nil, bundle: nil)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public required init?(coder: NSCoder) { nil }
|
|
152
|
+
|
|
153
|
+
/// Presented: the items go to the page's share sheet; once it answers,
|
|
154
|
+
/// the controller dismisses itself and reports.
|
|
155
|
+
open override func viewDidAppear(_ animated: Bool) {
|
|
156
|
+
super.viewDidAppear(animated)
|
|
157
|
+
guard !shared else { return }
|
|
158
|
+
shared = true
|
|
159
|
+
let params = sharePayload
|
|
160
|
+
let items = resolvedItems
|
|
161
|
+
Task { @MainActor in
|
|
162
|
+
let completed = await Self.shareOnPage(params)
|
|
163
|
+
self.dismiss(animated: animated)
|
|
164
|
+
self.completionWithItemsHandler?(nil, completed, completed ? items : nil, nil)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/// The items as shared: an item source's item for no particular activity.
|
|
169
|
+
var resolvedItems: [Any] {
|
|
170
|
+
activityItems.compactMap { item in
|
|
171
|
+
if let source = item as? any UIActivityItemSource { return source.activityViewController(self, itemForActivityType: nil) }
|
|
172
|
+
return item
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/// The `share` request's fields: `title` (an item source's link metadata
|
|
177
|
+
/// or subject), `text`, `url`, and the images as `files`, `bitmaps` or
|
|
178
|
+
/// `images`, as `ShareLink` sends them.
|
|
179
|
+
var sharePayload: _JSON {
|
|
180
|
+
var title: String?
|
|
181
|
+
var texts: [String] = []
|
|
182
|
+
var url: String?
|
|
183
|
+
var picture: [String: [_JSON]] = [:]
|
|
184
|
+
for item in activityItems {
|
|
185
|
+
if let source = item as? any UIActivityItemSource {
|
|
186
|
+
if title == nil { title = source.activityViewControllerLinkMetadata(self)?.title }
|
|
187
|
+
let subject = source.activityViewController(self, subjectForActivityType: nil)
|
|
188
|
+
if title == nil, !subject.isEmpty { title = subject }
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for item in resolvedItems {
|
|
192
|
+
switch item {
|
|
193
|
+
case let string as String: texts.append(string)
|
|
194
|
+
case let attributed as NSAttributedString: texts.append(attributed.string)
|
|
195
|
+
case let link as URL:
|
|
196
|
+
if url == nil { url = link.absoluteString } else { texts.append(link.absoluteString) }
|
|
197
|
+
case let image as UIImage:
|
|
198
|
+
for (key, value) in _PageFiles.fields(for: image, name: title ?? "Image") {
|
|
199
|
+
if case .array(let entries) = value { picture[key, default: []] += entries }
|
|
200
|
+
}
|
|
201
|
+
case let data as Data:
|
|
202
|
+
picture["files", default: []].append(_PageFiles.entry(name: title ?? "Shared", type: "application/octet-stream", data: data))
|
|
203
|
+
default: break
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
var fields: [String: _JSON] = [:]
|
|
207
|
+
if let title { fields["title"] = .string(title) }
|
|
208
|
+
if !texts.isEmpty { fields["text"] = .string(texts.joined(separator: "\n")) }
|
|
209
|
+
if let url { fields["url"] = .string(url) }
|
|
210
|
+
for (key, entries) in picture { fields[key] = .array(entries) }
|
|
211
|
+
return .object(fields)
|
|
212
|
+
}
|
|
213
|
+
}
|