Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vsanthanam/doc refactor #20

Merged
merged 2 commits into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions Sources/SafariView/DismissButtonStyle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SafariView
// DismissButtonStyle.swift
//
// MIT License
//
// Copyright (c) 2021 Varun Santhanam
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
//
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import SafariServices

public extension SafariView {

/// An enumeration describing the various dismiss buttons styles available in a ``SafariView``
enum DismissButtonStyle: Equatable, Hashable, Sendable {

/// The done dismiss button style.
case done

/// The close dismiss button style.
case close

/// The cancel dismiss button style.
case cancel

/// The default dismiss button style.
public static var `default`: DismissButtonStyle = .close

var uikit: SFSafariViewController.DismissButtonStyle {
switch self {
case .done: return .done
case .close: return .close
case .cancel: return .cancel
}
}

}

}
2 changes: 1 addition & 1 deletion Sources/SafariView/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private struct SafariViewDismissButtonStyleEnvironmentKey: EnvironmentKey {

typealias Value = SafariView.DismissButtonStyle

static var defaultValue: Value { .close }
static var defaultValue: Value { .default }

}

Expand Down
48 changes: 1 addition & 47 deletions Sources/SafariView/Presentation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ public extension View {
func safari(
url: Binding<URL?>,
onDismiss: (() -> Void)? = nil,
@ViewBuilder safariView: @escaping (URL) -> SafariView
@ViewBuilder safariView: @escaping (URL) -> SafariView = { url in SafariView(url: url) }
) -> some View {
safari(
item: url,
Expand All @@ -273,50 +273,4 @@ public extension View {
safariView: safariView
)
}

/// Presents a ``SafariView`` using the given URL as a data source for the ``SafariView``'s content
///
/// Use this method when you need to present a ``SafariView`` with content from a custom data source. The example below shows a custom data source `InventoryItem` that the closure uses to populate the ``SafariView`` before it is shown to the user:
///
/// ```swift
/// import Foundation
/// import SafariView
/// import SwiftUI
///
/// struct InventoryItem {
/// let title: String
/// let url: URL
/// }
///
/// struct InventoryList: View {
///
/// init(inventory: [InventoryItem]) {
/// self.inventory = inventory
/// }
///
/// var inventory: [InventoryItem]
///
/// @State private var selectedURL: URL?
///
/// var body: some View {
/// List(inventory.indices, id: \.self) { index in
/// Button(action: {
/// self.selectedURL = inventory[index].url
/// }) {
/// Text(inventory[index].title)
/// }
/// }
/// .safari(item: $selectedURL)
/// }
///
/// }
/// ```
///
/// - Parameters:
/// - url: A binding to an optional source of truth for the ``SafariView``. When the URL is non-nil, the system passes the URL to the modifier’s closure. You display this content in a ``SafariView`` that you create that the system displays to the user. If the URL changes, the system dismisses the ``SafariView`` and replaces it with a new one using the same process.
/// - onDismiss: The closure to execute when dismissing the ``SafariView``
/// - Returns: The modified view
func safari(url: Binding<URL?>, onDismiss: (() -> Void)? = nil) -> some View {
safari(url: url, onDismiss: onDismiss) { url in SafariView(url: url) }
}
}
51 changes: 51 additions & 0 deletions Sources/SafariView/PrewarmingToken.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SafariView
// PrewarmingToken.swift
//
// MIT License
//
// Copyright (c) 2021 Varun Santhanam
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
//
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import SafariServices

@available(iOS 15.0, macCatalyst 15.0, *)
public extension SafariView {

/// A type created when SafariServices begins prewarming a connection.
final class PrewarmingToken {

/// The URLs who's connections are being prewarmed.
public let urls: [URL]

/// Invalidate the prewarmed connections.
public func invalidate() {
token.invalidate()
}

init(_ token: SFSafariViewController.PrewarmingToken, urls: [URL]) {
self.token = token
self.urls = urls
}

private let token: SFSafariViewController.PrewarmingToken

}

}
10 changes: 0 additions & 10 deletions Sources/SafariView/SafariView.docc/Environment.md

This file was deleted.

2 changes: 2 additions & 0 deletions Sources/SafariView/SafariView.docc/ExcludedActivityTypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
@DocumentationExtension(mergeBehavior: append)
}

## Overview

You can initialize instances of this type using an array literal of `UIActivity.ActivityType` values. For example:

```swift
Expand Down
2 changes: 2 additions & 0 deletions Sources/SafariView/SafariView.docc/IncludedActivities.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
@DocumentationExtension(mergeBehavior: append)
}

## Overview

You can initialize instances of this type using an array literal of `UIActivity` values. For example:

```swift
Expand Down
30 changes: 0 additions & 30 deletions Sources/SafariView/SafariView.docc/Modifiers.md

This file was deleted.

23 changes: 2 additions & 21 deletions Sources/SafariView/SafariView.docc/SafariView.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,10 @@ SafariServices in SwiftUI

## Overview

`SafariView` is a wrapper around [`SFSafariViewController`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) for use within SwiftUI applications. The view includes Safari features such as Reader, AutoFill, Fraudulent Website Detection, and content blocking. The user's activity and interaction with `SafariView` are not visible to your app, which cannot access AutoFill data, browsing history, or website data. You do not need to secure data between your app and Safari. If you would like to share data between your app and Safari, so it is easier for a user to log in only one time, use [`ASWebAuthenticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) instead.

- Important: In accordance with [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/), this view must be used to visibly present information to users; the view may not be hidden or obscured by other views or layers. Additionally, an app may not use `SafariView` to track users without their knowledge and consent.

UI features include the following:
- A read-only address field with a security indicator and a Reader button
- An Action button that invokes an activity view controller offering custom services from your app, and activities, such as messaging, from the system and other extensions
- A Done button, back and forward navigation buttons, and a button to open the page directly in Safari

The library contains a single `View`-conforming struct, also named `SafariView`, as well as several view modifiers used to control the appearance, behavior and presentation of a ``SafariView/SafariView``

- Note: In Mac apps built with Mac Catalyst, SafariView launches the default web browser instead of displaying a modal window. SafariView is not compatible with macOS, tvOS, or watchOS.
`SafariView` is a package that wraps [`SafariServices`](https://developer.apple.com/documentation/safariservices/) for use with SwiftUI applications. Currently, it contains a single SwiftUI view, also called `SafariView`, which wraps [`SFSafariViewController`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller).

## Topics

### Views

- ``SafariView``

### Modifiers

- ``SwiftUI/View``

### Environment

- ``SwiftUI/EnvironmentValues``
- ``SafariView/SafariView``
58 changes: 54 additions & 4 deletions Sources/SafariView/SafariView.docc/View.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,29 @@
@DocumentationExtension(mergeBehavior: append)
}

A SafariView is best presented by using one the `safari` view modifiers, or via sheet presentation, though it does work in other scenarios as well. For configuration, appearance, and presentation options, see the documentation for the included view modifiers here: ``SwiftUI/View``.
## Overview

The view includes Safari features such as Reader, AutoFill, Fraudulent Website Detection, and content blocking. The user's activity and interaction with `SafariView` are not visible to your app, which cannot access AutoFill data, browsing history, or website data. You do not need to secure data between your app and Safari. If you would like to share data between your app and Safari, so it is easier for a user to log in only one time, use [`ASWebAuthenticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) instead.

- Important: In accordance with [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/), this view must be used to visibly present information to users; the view may not be hidden or obscured by other views or layers. Additionally, an app may not use `SafariView` to track users without their knowledge and consent.

UI features include the following:
- A read-only address field with a security indicator and a Reader button
- An Action button that invokes an activity view controller offering custom services from your app, and activities, such as messaging, from the system and other extensions
- A Done button, back and forward navigation buttons, and a button to open the page directly in Safari

The library contains a single `View`-conforming struct, also named `SafariView`, as well as several view modifiers used to control the appearance, behavior and presentation of a ``SafariView/SafariView``

- Note: In Mac apps built with Mac Catalyst, SafariView launches the default web browser instead of displaying a modal window. SafariView is not compatible with macOS, tvOS, or watchOS.

You can present a `SafariView` using the built-in presentation view modifiers:

- ``SwiftUI/View/safari(isPresented:onDismiss:safariView:)``
- ``SwiftUI/View/safari(url:onDismiss:safariView:)``
- ``SwiftUI/View/safari(item:onDismiss:safariView:)``
- ``SwiftUI/View/safari(item:id:onDismiss:safariView:)``

You can also use sheet presentation, or any other presentation mechanism of your choice.

## Topics

Expand All @@ -14,10 +36,24 @@ A SafariView is best presented by using one the `safari` view modifiers, or via
- ``init(url:activityButton:onInitialLoad:onInitialRedirect:onOpenInBrowser:)``
- ``init(url:activityButton:eventAttribution:onInitialLoad:onInitialRedirect:onOpenInBrowser:)``

### Custom Activities
### Configuration

- ``IncludedActivities``
- ``ExcludedActivityTypes``
- ``SwiftUI/View/safariEntersReaderIfAvailable(_:)``
- ``SwiftUI/View/safariBarCollapsingEnabled(_:)``

### Appearance

- ``SwiftUI/View/safariBarTintColor(_:)``
- ``SwiftUI/View/safariControlTintColor(_:)``
- ``SwiftUI/View/safariDismissButtonStyle(_:)``
- ``SafariView/SafariView/DismissButtonStyle``

### Presentation

- ``SwiftUI/View/safari(isPresented:onDismiss:safariView:)``
- ``SwiftUI/View/safari(url:onDismiss:safariView:)``
- ``SwiftUI/View/safari(item:onDismiss:safariView:)``
- ``SwiftUI/View/safari(item:id:onDismiss:safariView:)``

### Connection Prewarming

Expand All @@ -28,3 +64,17 @@ A SafariView is best presented by using one the `safari` view modifiers, or via

- ``clearWebsiteData()``
- ``clearWebsiteData(completionHandler:)``

### Custom Activities

- ``SwiftUI/View/includedSafariActivities(_:)-2u8l9``
- ``SwiftUI/View/includedSafariActivities(_:)-362lz``
- ``SafariView/SafariView/IncludedActivities``
- ``SwiftUI/View/excludedSafariActivityTypes(_:)-tvrg``
- ``SwiftUI/View/excludedSafariActivityTypes(_:)-1v8zq``
- ``SafariView/SafariView/ExcludedActivityTypes``

### Environment Values

- ``SwiftUI/EnvironmentValues/safariViewIncludedActivities``
- ``SwiftUI/EnvironmentValues/safariViewExcludedActivityTypes``
15 changes: 4 additions & 11 deletions Sources/SafariView/SafariView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,10 @@ public struct SafariView: View {

// MARK: - API

/// A convenience typealias for [`SFSafariViewController.DismissButtonStyle`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/dismissbuttonstyle)
public typealias DismissButtonStyle = SFSafariViewController.DismissButtonStyle

/// A convenience typealias for [`SFSafariViewController.ActivityButton`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/activitybutton)
@available(iOS 15.0, macCatalyst 15.0, *)
public typealias ActivityButton = SFSafariViewController.ActivityButton

/// A convenience typealias for [`SFSafariViewController.PrewarmingToken`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller/prewarmingtoken)
///
/// You can generate prewarming tokens for invalidation using the ``prewarmConnections(to:)`` static method.
@available(iOS 15.0, macCatalyst 15.0, *)
public typealias PrewarmingToken = SFSafariViewController.PrewarmingToken

/// Prewarm the connection to a list of provided URLs
///
/// You can use this returned value of this method to invalidate the prewarmed cache by invoking the `invaldate()` method on the token.
Expand All @@ -133,7 +124,8 @@ public struct SafariView: View {
@available(iOS 15.0, macCatalyst 15.0, *)
@discardableResult
public static func prewarmConnections(to URLs: [URL]) -> PrewarmingToken {
SFSafariViewController.prewarmConnections(to: URLs)
let token = SFSafariViewController.prewarmConnections(to: URLs)
return .init(token, urls: URLs)
}

/// Clears the safari view's cache using [Swift Concurrency](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/).
Expand All @@ -151,6 +143,7 @@ public struct SafariView: View {

// MARK: - View

@_documentation(visibility: internal)
public var body: some View {
Safari(parent: self)
.ignoresSafeArea(.container, edges: .all)
Expand Down Expand Up @@ -189,7 +182,7 @@ public struct SafariView: View {
private func apply(to controller: SFSafariViewController) {
controller.preferredBarTintColor = barTintColor.map(UIColor.init)
controller.preferredControlTintColor = UIColor(controlTintColor)
controller.dismissButtonStyle = dismissButtonStyle
controller.dismissButtonStyle = dismissButtonStyle.uikit
}

private func buildConfiguration() -> SFSafariViewController.Configuration {
Expand Down