Skip to content

Commit 518296c

Browse files
authored
Add additional presentation modifier for SafariView (#35)
1 parent d05f53d commit 518296c

File tree

9 files changed

+279
-86
lines changed

9 files changed

+279
-86
lines changed

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/SafariUI/SafariUI.docc/SafariView.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ You can present a `SafariView` using the built-in presentation view modifiers:
2323
- ``SwiftUI/View/safari(isPresented:url:onDismiss:)``
2424
- ``SwiftUI/View/safari(item:onDismiss:safariView:)``
2525
- ``SwiftUI/View/safari(item:id:onDismiss:safariView:)``
26+
- ``SwiftUI/View/safari(url:onDismiss:)``
2627

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

Sources/SafariUI/SafariUI.docc/View.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ SwiftUI view modifiers used to configure a ``SafariView`` or a ``WebAuthenticati
2121
- ``SwiftUI/View/safari(isPresented:url:onDismiss:)``
2222
- ``SwiftUI/View/safari(item:onDismiss:safariView:)``
2323
- ``SwiftUI/View/safari(item:id:onDismiss:safariView:)``
24+
- ``SwiftUI/View/safari(url:onDismiss:)``
2425

2526
### SafarView Custom Activities
2627

Sources/SafariView/Modifiers.swift

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ public extension View {
3535
/// - Parameter entersReaderIfAvailable: Whether or not the safari view should automatically enter reader mode if available.
3636
/// - Returns: The modified view
3737
func safariEntersReaderIfAvailable(_ entersReaderIfAvailable: Bool = true) -> some View {
38-
let modifier = SafariViewEntersReaderIfAvailableModifier(entersReaderIfAvailable: entersReaderIfAvailable)
39-
return ModifiedContent(content: self, modifier: modifier)
38+
ModifiedContent(
39+
content: self,
40+
modifier: SafariViewEntersReaderIfAvailableModifier(entersReaderIfAvailable: entersReaderIfAvailable)
41+
)
4042
}
4143

4244
/// Set the bar collapsing behavior of safari views within this view
@@ -46,8 +48,10 @@ public extension View {
4648
/// - Parameter barCollapsingEnabled: Whether or not bar collpasing should be enabled.
4749
/// - Returns: The modified view
4850
func safariBarCollapsingEnabled(_ barCollapsingEnabled: Bool = true) -> some View {
49-
let modifier = SafariViewBarCollapsingEnabledModifier(barCollapsingEnabled: barCollapsingEnabled)
50-
return ModifiedContent(content: self, modifier: modifier)
51+
ModifiedContent(
52+
content: self,
53+
modifier: SafariViewBarCollapsingEnabledModifier(barCollapsingEnabled: barCollapsingEnabled)
54+
)
5155
}
5256

5357
/// Set the bar tint color of safari views within this view
@@ -57,8 +61,10 @@ public extension View {
5761
/// - Parameter color: The color to use, or `nil` for the system default
5862
/// - Returns: The modified view
5963
func safariBarTintColor(_ color: Color?) -> some View {
60-
let modifier = SafariViewBarTintColorModifier(safariViewBarTintColor: color)
61-
return ModifiedContent(content: self, modifier: modifier)
64+
ModifiedContent(
65+
content: self,
66+
modifier: SafariViewBarTintColorModifier(safariViewBarTintColor: color)
67+
)
6268
}
6369

6470
/// Set the control tint color of safari views within this view
@@ -68,8 +74,10 @@ public extension View {
6874
/// - Parameter color: The color to use
6975
/// - Returns: The modified view
7076
func safariControlTintColor(_ color: Color) -> some View {
71-
let modifier = SafariViewControlTintColorModifier(safariViewControlTintColor: color)
72-
return ModifiedContent(content: self, modifier: modifier)
77+
ModifiedContent(
78+
content: self,
79+
modifier: SafariViewControlTintColorModifier(safariViewControlTintColor: color)
80+
)
7381
}
7482

7583
/// Set the safari view's dismiss button style
@@ -107,8 +115,10 @@ public extension View {
107115
/// - Parameter activities: The activities to include. You may use an array literal of `UIActivity` types.
108116
/// - Returns: The modified content
109117
func includedSafariActivities(_ activities: SafariView.IncludedActivities) -> some View {
110-
let modifier = SafariViewIncludedActivitiesModifier(activities: activities)
111-
return ModifiedContent(content: self, modifier: modifier)
118+
ModifiedContent(
119+
content: self,
120+
modifier: SafariViewIncludedActivitiesModifier(activities: activities)
121+
)
112122
}
113123

114124
/// Conditionally include activities in the share sheet of safari views within this view.
@@ -138,9 +148,12 @@ public extension View {
138148
/// - Parameter activities: Closure used to conditionally include activities
139149
/// - Returns: The modified content
140150
func includedSafariActivities(_ activities: @escaping (_ url: URL, _ pageTitle: String?) -> [UIActivity]) -> some View {
141-
let activities = SafariView.IncludedActivities(activities)
142-
let modifier = SafariViewIncludedActivitiesModifier(activities: activities)
143-
return ModifiedContent(content: self, modifier: modifier)
151+
ModifiedContent(
152+
content: self,
153+
modifier: SafariViewIncludedActivitiesModifier(
154+
activities: .init(activities)
155+
)
156+
)
144157
}
145158

146159
/// Exclude activity types from the share sheet of safari views within this view.
@@ -167,8 +180,10 @@ public extension View {
167180
/// - Parameter activityTypes: The activity types to exclude. You may use an array literal of `UIActivity.ActivityType` values.
168181
/// - Returns: The modified content
169182
func excludedSafariActivityTypes(_ activityTypes: SafariView.ExcludedActivityTypes) -> some View {
170-
let modifier = SafariViewExcludedActivityTypesModifier(activityTypes: activityTypes)
171-
return ModifiedContent(content: self, modifier: modifier)
183+
ModifiedContent(
184+
content: self,
185+
modifier: SafariViewExcludedActivityTypesModifier(activityTypes: activityTypes)
186+
)
172187
}
173188

174189
/// Conditionally exclude activity types from the share sheet of safari views within this view.
@@ -196,10 +211,15 @@ public extension View {
196211
///
197212
/// - Parameter activityTypes: Closure used to conditionally exclude activities
198213
/// - Returns: The modified content
199-
func excludedSafariActivityTypes(_ activityTypes: @escaping (_ url: URL, _ pageTitle: String?) -> [UIActivity.ActivityType]) -> some View {
200-
let activityTypes = SafariView.ExcludedActivityTypes(activityTypes)
201-
let modifier = SafariViewExcludedActivityTypesModifier(activityTypes: activityTypes)
202-
return ModifiedContent(content: self, modifier: modifier)
214+
func excludedSafariActivityTypes(
215+
_ activityTypes: @escaping (_ url: URL, _ pageTitle: String?) -> [UIActivity.ActivityType]
216+
) -> some View {
217+
ModifiedContent(
218+
content: self,
219+
modifier: SafariViewExcludedActivityTypesModifier(
220+
activityTypes: .init(activityTypes)
221+
)
222+
)
203223
}
204224

205225
}

Sources/SafariView/BoolPresentation.swift renamed to Sources/SafariView/Presentation/BoolPresentation.swift

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -86,62 +86,6 @@ public extension View {
8686
)
8787
}
8888

89-
/// Presents a ``SafariView`` when a binding to a Boolean value that you provide is `true`.
90-
///
91-
/// Use this method when you want to present a ``SafariView`` to the user when a Boolean value you provide is true.
92-
/// The example below displays a modal view of the mockup for a software license agreement when the user toggles the `isShowingSafari` variable by clicking or tapping on the “Show License Agreement” button:
93-
///
94-
/// ```swift
95-
/// import Foundation
96-
/// import SafariView
97-
/// import SwiftUI
98-
///
99-
/// struct ShowLicenseAgreement: View {
100-
///
101-
/// let licenseAgreementURL: URL
102-
///
103-
/// @State private var isShowingSafari = false
104-
///
105-
/// var body: some View {
106-
/// Button {
107-
/// isShowingSafari.toggle()
108-
/// } label: {
109-
/// Text("Show License Agreement")
110-
/// }
111-
/// .safari(isPresented: $isShowingSafari,
112-
/// url: licenseAgreementURL
113-
/// onDismiss: didDismiss)
114-
/// }
115-
///
116-
/// func didDismiss() {
117-
/// // Handle the dismissing action.
118-
/// }
119-
///
120-
/// }
121-
/// ```
122-
///
123-
/// - Parameters:
124-
/// - isPresented: A binding to a Boolean value that determines whether to present the ``SafariView`` that you create in the modifier’s content closure.
125-
/// - url: The URL to load in the presented ``SafariView``
126-
/// - onDismiss: The closure to execute when dismissing the ``SafariView``
127-
/// - Returns: The modified view
128-
func safari(
129-
isPresented: Binding<Bool>,
130-
url: URL,
131-
onDismiss: (() -> Void)? = nil
132-
) -> some View {
133-
ModifiedContent(
134-
content: self,
135-
modifier: IsPresentedModifier(
136-
isPresented: isPresented,
137-
safariView: SafariView(
138-
url: url
139-
),
140-
onDismiss: onDismiss
141-
)
142-
)
143-
}
144-
14589
}
14690

14791
@available(iOS 14.0, macCatalyst 14.0, *)
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// SafariUI
2+
// BoolURLPresentation.swift
3+
//
4+
// MIT License
5+
//
6+
// Copyright (c) 2023 Varun Santhanam
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files (the Software), to deal
9+
//
10+
// in the Software without restriction, including without limitation the rights
11+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
// copies of the Software, and to permit persons to whom the Software is
13+
// furnished to do so, subject to the following conditions:
14+
//
15+
// The above copyright notice and this permission notice shall be included in all
16+
// copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
// SOFTWARE.
25+
26+
import Foundation
27+
import SwiftUI
28+
29+
@available(iOS 14.0, macCatalyst 14.0, *)
30+
public extension View {
31+
32+
/// Presents a ``SafariView`` when a binding to a Boolean value that you provide is `true`.
33+
///
34+
/// Use this method when you want to present a ``SafariView`` to the user when a Boolean value you provide is true.
35+
/// The example below displays a modal view of the mockup for a software license agreement when the user toggles the `isShowingSafari` variable by clicking or tapping on the “Show License Agreement” button:
36+
///
37+
/// ```swift
38+
/// import Foundation
39+
/// import SafariView
40+
/// import SwiftUI
41+
///
42+
/// struct ShowLicenseAgreement: View {
43+
///
44+
/// let licenseAgreementURL: URL
45+
///
46+
/// @State private var isShowingSafari = false
47+
///
48+
/// var body: some View {
49+
/// Button {
50+
/// isShowingSafari.toggle()
51+
/// } label: {
52+
/// Text("Show License Agreement")
53+
/// }
54+
/// .safari(isPresented: $isShowingSafari,
55+
/// url: licenseAgreementURL
56+
/// onDismiss: didDismiss)
57+
/// }
58+
///
59+
/// func didDismiss() {
60+
/// // Handle the dismissing action.
61+
/// }
62+
///
63+
/// }
64+
/// ```
65+
///
66+
/// - Parameters:
67+
/// - isPresented: A binding to a Boolean value that determines whether to present the ``SafariView`` that you create in the modifier’s content closure.
68+
/// - url: The URL to load in the presented ``SafariView``
69+
/// - onDismiss: The closure to execute when dismissing the ``SafariView``
70+
/// - Returns: The modified view
71+
func safari(
72+
isPresented: Binding<Bool>,
73+
url: URL,
74+
onDismiss: (() -> Void)? = nil
75+
) -> some View {
76+
ModifiedContent(
77+
content: self,
78+
modifier: BoolURLPresentation(
79+
isPresented: isPresented,
80+
onDismiss: onDismiss,
81+
url: url
82+
)
83+
)
84+
}
85+
86+
}
87+
88+
@available(iOS 14.0, macCatalyst 14.0, *)
89+
private struct BoolURLPresentation: ViewModifier {
90+
91+
init(
92+
isPresented: Binding<Bool>,
93+
onDismiss: (() -> Void)?,
94+
url: URL
95+
) {
96+
_isPresented = isPresented
97+
self.onDismiss = onDismiss
98+
self.url = url
99+
}
100+
101+
@MainActor
102+
@ViewBuilder
103+
func body(content: Content) -> some View {
104+
content
105+
.safari(
106+
isPresented: $isPresented,
107+
onDismiss: onDismiss
108+
) {
109+
SafariView(url: url)
110+
}
111+
}
112+
113+
@Binding
114+
private var isPresented: Bool
115+
private let onDismiss: (() -> Void)?
116+
private let url: URL
117+
118+
}
File renamed without changes.

0 commit comments

Comments
 (0)