diff --git a/Sources/SafariUI/SafariUI.docc/SafariView.md b/Sources/SafariUI/SafariUI.docc/SafariView.md index 5a3ca8ad6..9fb462ac3 100644 --- a/Sources/SafariUI/SafariUI.docc/SafariView.md +++ b/Sources/SafariUI/SafariUI.docc/SafariView.md @@ -19,8 +19,8 @@ UI features include the following: You can present a `SafariView` using the built-in presentation view modifiers: -- ``SwiftUI/View/safari(isPresented:onDismiss:safariView:)`` -- ``SwiftUI/View/safari(isPresented:url:onDismiss:)`` +- ``SwiftUI/View/safari(isPresented:presentationStyle:onDismiss:safariView:)`` +- ``SwiftUI/View/safari(isPresented:url:presentationStyle:onDismiss:)`` - ``SwiftUI/View/safari(item:onDismiss:safariView:)`` - ``SwiftUI/View/safari(item:id:onDismiss:safariView:)`` - ``SwiftUI/View/safari(url:onDismiss:)`` diff --git a/Sources/SafariUI/SafariUI.docc/View.md b/Sources/SafariUI/SafariUI.docc/View.md index 113f9e732..4a1e3988d 100644 --- a/Sources/SafariUI/SafariUI.docc/View.md +++ b/Sources/SafariUI/SafariUI.docc/View.md @@ -17,8 +17,8 @@ SwiftUI view modifiers used to configure a ``SafariView`` or a ``WebAuthenticati ### SafariView Presentation -- ``SwiftUI/View/safari(isPresented:onDismiss:safariView:)`` -- ``SwiftUI/View/safari(isPresented:url:onDismiss:)`` +- ``SwiftUI/View/safari(isPresented:presentationStyle:onDismiss:safariView:)`` +- ``SwiftUI/View/safari(isPresented:url:presentationStyle:onDismiss:)`` - ``SwiftUI/View/safari(item:onDismiss:safariView:)`` - ``SwiftUI/View/safari(item:id:onDismiss:safariView:)`` - ``SwiftUI/View/safari(url:onDismiss:)`` diff --git a/Sources/SafariView/Presentation/BoolPresentation.swift b/Sources/SafariView/Presentation/BoolPresentation.swift index db26355ef..d2c8877b3 100644 --- a/Sources/SafariView/Presentation/BoolPresentation.swift +++ b/Sources/SafariView/Presentation/BoolPresentation.swift @@ -68,11 +68,13 @@ public extension View { /// /// - Parameters: /// - isPresented: A binding to a Boolean value that determines whether to present the ``SafariView`` that you create in the modifier’s content closure. + /// - presentationStyle: The ``SafariView/PresentationStyle`` used to present the ``SafariView``. /// - onDismiss: The closure to execute when dismissing the ``SafariView`` /// - safariView: A closure that returns the ``SafariView`` to present /// - Returns: The modified view func safari( isPresented: Binding, + presentationStyle: SafariView.PresentationStyle = .default, onDismiss: (() -> Void)? = nil, safariView: () -> SafariView ) -> some View { @@ -80,6 +82,7 @@ public extension View { content: self, modifier: IsPresentedModifier( isPresented: isPresented, + presentationStyle: presentationStyle, safariView: safariView(), onDismiss: onDismiss ) @@ -95,10 +98,12 @@ private struct IsPresentedModifier: ViewModifier { init( isPresented: Binding, + presentationStyle: SafariView.PresentationStyle, safariView: SafariView, onDismiss: (() -> Void)? ) { self.isPresented = isPresented + self.presentationStyle = presentationStyle self.safariView = safariView self.onDismiss = onDismiss } @@ -113,6 +118,7 @@ private struct IsPresentedModifier: ViewModifier { Presenter( isPresented: isPresented, url: safariView.url, + presentationStyle: presentationStyle, onInitialLoad: safariView.onInitialLoad, onInitialRedirect: safariView.onInitialRedirect, onOpenInBrowser: safariView.onOpenInBrowser, @@ -130,6 +136,7 @@ private struct IsPresentedModifier: ViewModifier { init( isPresented: Binding, url: URL, + presentationStyle: SafariView.PresentationStyle, onInitialLoad: ((Bool) -> Void)?, onInitialRedirect: ((URL) -> Void)?, onOpenInBrowser: (() -> Void)?, @@ -139,6 +146,7 @@ private struct IsPresentedModifier: ViewModifier { ) { _isPresented = isPresented self.url = url + self.presentationStyle = presentationStyle self.onInitialLoad = onInitialLoad self.onInitialRedirect = onInitialRedirect self.onOpenInBrowser = onOpenInBrowser @@ -153,6 +161,7 @@ private struct IsPresentedModifier: ViewModifier { .init( isPresented: isPresented, url: url, + presentationStyle: presentationStyle, bindingSetter: { newValue in isPresented = newValue }, onInitialLoad: onInitialLoad, onInitialRedirect: onInitialRedirect, @@ -191,6 +200,7 @@ private struct IsPresentedModifier: ViewModifier { init( isPresented: Bool, url: URL, + presentationStyle: SafariView.PresentationStyle, bindingSetter: @escaping (Bool) -> Void, onInitialLoad: ((Bool) -> Void)?, onInitialRedirect: ((URL) -> Void)?, @@ -201,6 +211,7 @@ private struct IsPresentedModifier: ViewModifier { ) { self.isPresented = isPresented self.url = url + self.presentationStyle = presentationStyle self.bindingSetter = bindingSetter self.onInitialLoad = onInitialLoad self.onInitialRedirect = onInitialRedirect @@ -272,6 +283,7 @@ private struct IsPresentedModifier: ViewModifier { private weak var safariViewController: SFSafariViewController? private let url: URL + private let presentationStyle: SafariView.PresentationStyle private let bindingSetter: (Bool) -> Void private let onInitialLoad: ((Bool) -> Void)? private let onInitialRedirect: ((URL) -> Void)? @@ -286,6 +298,14 @@ private struct IsPresentedModifier: ViewModifier { vc.preferredBarTintColor = barTintColor.map(UIColor.init) vc.preferredControlTintColor = UIColor(controlTintColor) vc.dismissButtonStyle = dismissButtonStyle.uikit + switch presentationStyle { + case .standard: + break + case .formSheet: + vc.modalPresentationStyle = .formSheet + case .pageSheet: + vc.modalPresentationStyle = .pageSheet + } guard let presenting = view.controller else { bindingSetter(false) return @@ -347,6 +367,7 @@ private struct IsPresentedModifier: ViewModifier { private var excludedActivityTypes: SafariView.ExcludedActivityTypes private let url: URL + private let presentationStyle: SafariView.PresentationStyle private let onInitialLoad: ((Bool) -> Void)? private let onInitialRedirect: ((URL) -> Void)? private let onOpenInBrowser: (() -> Void)? @@ -357,6 +378,7 @@ private struct IsPresentedModifier: ViewModifier { } private let isPresented: Binding + private let presentationStyle: SafariView.PresentationStyle private let safariView: SafariView private let onDismiss: (() -> Void)? diff --git a/Sources/SafariView/Presentation/BoolURLPresentation.swift b/Sources/SafariView/Presentation/BoolURLPresentation.swift index 12d5d9f8b..8b3338416 100644 --- a/Sources/SafariView/Presentation/BoolURLPresentation.swift +++ b/Sources/SafariView/Presentation/BoolURLPresentation.swift @@ -66,19 +66,22 @@ public extension View { /// - Parameters: /// - isPresented: A binding to a Boolean value that determines whether to present the ``SafariView`` that you create in the modifier’s content closure. /// - url: The URL to load in the presented ``SafariView`` + /// - presentationStyle: The ``SafariView/PresentationStyle`` used to present the ``SafariView``. /// - onDismiss: The closure to execute when dismissing the ``SafariView`` /// - Returns: The modified view func safari( isPresented: Binding, url: URL, + presentationStyle: SafariView.PresentationStyle = .default, onDismiss: (() -> Void)? = nil ) -> some View { ModifiedContent( content: self, modifier: BoolURLPresentation( isPresented: isPresented, - onDismiss: onDismiss, - url: url + url: url, + presentationStyle: presentationStyle, + onDismiss: onDismiss ) ) } @@ -89,12 +92,14 @@ private struct BoolURLPresentation: ViewModifier { init( isPresented: Binding, - onDismiss: (() -> Void)?, - url: URL + url: URL, + presentationStyle: SafariView.PresentationStyle, + onDismiss: (() -> Void)? ) { _isPresented = isPresented - self.onDismiss = onDismiss self.url = url + self.presentationStyle = presentationStyle + self.onDismiss = onDismiss } @MainActor @@ -103,6 +108,7 @@ private struct BoolURLPresentation: ViewModifier { content .safari( isPresented: $isPresented, + presentationStyle: presentationStyle, onDismiss: onDismiss ) { SafariView(url: url) @@ -111,7 +117,8 @@ private struct BoolURLPresentation: ViewModifier { @Binding private var isPresented: Bool - private let onDismiss: (() -> Void)? private let url: URL + private let presentationStyle: SafariView.PresentationStyle + private let onDismiss: (() -> Void)? } diff --git a/Sources/SafariView/Presentation/PresentationStyle.swift b/Sources/SafariView/Presentation/PresentationStyle.swift new file mode 100644 index 000000000..ee9447fd9 --- /dev/null +++ b/Sources/SafariView/Presentation/PresentationStyle.swift @@ -0,0 +1,36 @@ +// SafariUI +// PresentationStyle.swift +// +// MIT License +// +// Copyright (c) 2023 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. + +@available(iOS 14.0, visionOS 1.0, macCatalyst 14.0, *) +public extension SafariView { + + enum PresentationStyle: Equatable, Hashable, Sendable, Codable { + case standard + case formSheet + case pageSheet + public static let `default`: PresentationStyle = .standard + } + +}