Introduces limited iOS 13 support – wip
This commit is contained in:
parent
19a7cf0b27
commit
0ad99191d9
|
@ -29,7 +29,6 @@ import ObjectiveC
|
|||
/// }
|
||||
///
|
||||
public struct Backport<Wrapped> {
|
||||
|
||||
/// The underlying content this backport represents.
|
||||
public let content: Wrapped
|
||||
|
||||
|
@ -38,7 +37,12 @@ public struct Backport<Wrapped> {
|
|||
public init(_ content: Wrapped) {
|
||||
self.content = content
|
||||
}
|
||||
}
|
||||
|
||||
public extension Backport where Wrapped == Any {
|
||||
init(_ content: Wrapped) {
|
||||
self.content = content
|
||||
}
|
||||
}
|
||||
|
||||
public extension View {
|
||||
|
|
|
@ -165,7 +165,6 @@ struct PasteButtonStyle: PrimitiveButtonStyle {
|
|||
}
|
||||
}
|
||||
}
|
||||
// .opacity(configuration.isPressed ? 0.5 : 1)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,9 @@ internal extension View {
|
|||
library: PHPhotoLibrary
|
||||
) -> some View {
|
||||
if #available(iOS 14, *) {
|
||||
sheet(isPresented: isPresented) {
|
||||
|
||||
}
|
||||
// var config = PHPickerConfiguration(photoLibrary: library)
|
||||
// config.preferredAssetRepresentationMode = preferredItemEncoding.mode
|
||||
// config.selectionLimit = maxSelectionCount ?? 0
|
||||
|
@ -29,13 +32,15 @@ internal extension View {
|
|||
// configuration: config
|
||||
// )
|
||||
} else {
|
||||
EmptyView()
|
||||
backport.background {
|
||||
LegacyPhotosViewController(isPresented: isPresented, selection: selection, filter: filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
private struct PickerViewController: UIViewControllerRepresentable {
|
||||
private struct PhotosViewController: UIViewControllerRepresentable {
|
||||
@Binding var isPresented: Bool
|
||||
@Binding var selection: [Backport<Any>.PhotosPickerItem]
|
||||
|
||||
|
@ -57,7 +62,7 @@ private struct PickerViewController: UIViewControllerRepresentable {
|
|||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
private extension PickerViewController {
|
||||
private extension PhotosViewController {
|
||||
final class Representable: UIViewController, PHPickerViewControllerDelegate, UIAdaptivePresentationControllerDelegate {
|
||||
private weak var controller: PHPickerViewController?
|
||||
|
||||
|
@ -105,17 +110,121 @@ private extension PickerViewController {
|
|||
}
|
||||
|
||||
private func dismissController() {
|
||||
isPresented.wrappedValue = false
|
||||
guard let controller else { return }
|
||||
controller.presentedViewController?.dismiss(animated: true)
|
||||
}
|
||||
|
||||
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
||||
print(results)
|
||||
dismissController()
|
||||
}
|
||||
|
||||
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
||||
dismissController()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
||||
print(results)
|
||||
#warning("TBD")
|
||||
@available(iOS 13, *)
|
||||
private struct LegacyPhotosViewController: UIViewControllerRepresentable {
|
||||
@Binding var isPresented: Bool
|
||||
@Binding var selection: [Backport<Any>.PhotosPickerItem]
|
||||
|
||||
let filter: Backport<Any>.PHPickerFilter?
|
||||
|
||||
func makeUIViewController(context: Context) -> Representable {
|
||||
Representable(
|
||||
isPresented: $isPresented,
|
||||
selection: $selection,
|
||||
filter: filter
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
func updateUIViewController(_ controller: Representable, context: Context) {
|
||||
controller.selection = $selection
|
||||
controller.filter = filter
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
private extension LegacyPhotosViewController {
|
||||
final class Representable: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIAdaptivePresentationControllerDelegate {
|
||||
private weak var controller: UIImagePickerController?
|
||||
|
||||
var isPresented: Binding<Bool> {
|
||||
didSet {
|
||||
updateControllerLifecycle(
|
||||
from: oldValue.wrappedValue,
|
||||
to: isPresented.wrappedValue
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var selection: Binding<[Backport<Any>.PhotosPickerItem]>
|
||||
var filter: Backport<Any>.PHPickerFilter?
|
||||
|
||||
init(isPresented: Binding<Bool>, selection: Binding<[Backport<Any>.PhotosPickerItem]>, filter: Backport<Any>.PHPickerFilter?) {
|
||||
self.isPresented = isPresented
|
||||
self.selection = selection
|
||||
self.filter = filter
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func updateControllerLifecycle(from oldValue: Bool, to newValue: Bool) {
|
||||
switch (oldValue, newValue) {
|
||||
case (false, true):
|
||||
presentController()
|
||||
case (true, false):
|
||||
dismissController()
|
||||
case (true, true), (false, false):
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func presentController() {
|
||||
let controller = UIImagePickerController()
|
||||
|
||||
if let filter {
|
||||
controller.mediaTypes = filter.mediaTypes
|
||||
} else if let types = UIImagePickerController.availableMediaTypes(for: .photoLibrary) {
|
||||
controller.mediaTypes = types
|
||||
}
|
||||
|
||||
controller.allowsEditing = false
|
||||
controller.sourceType = .photoLibrary
|
||||
controller.videoQuality = .typeHigh
|
||||
controller.presentationController?.delegate = self
|
||||
controller.delegate = self
|
||||
|
||||
present(controller, animated: true)
|
||||
self.controller = controller
|
||||
}
|
||||
|
||||
private func dismissController() {
|
||||
isPresented.wrappedValue = false
|
||||
guard let controller else { return }
|
||||
controller.presentedViewController?.dismiss(animated: true)
|
||||
}
|
||||
|
||||
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
|
||||
print("TBD")
|
||||
print(info)
|
||||
dismissController()
|
||||
}
|
||||
|
||||
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
||||
dismissController()
|
||||
}
|
||||
|
||||
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
||||
dismissController()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,22 +2,22 @@
|
|||
import SwiftUI
|
||||
import PhotosUI
|
||||
|
||||
@available(iOS, introduced: 14, deprecated: 16)
|
||||
public extension Backport where Wrapped == Any {
|
||||
// Available when SwiftUI is imported with PhotosUI
|
||||
@available(iOS, introduced: 13, deprecated: 16)
|
||||
public extension Backport<Any> {
|
||||
/// Available when SwiftUI is imported with PhotosUI
|
||||
/// A control that allows a user to choose photos and/or videos from the photo library.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
struct PhotosPicker<Label>: View where Label: View {
|
||||
@State private var isPresented: Bool = false
|
||||
@Binding var selection: [Backport<Any>.PhotosPickerItem]
|
||||
@Binding var selection: [Backport.PhotosPickerItem]
|
||||
|
||||
private let filter: Backport<Any>.PHPickerFilter?
|
||||
private let maxSelection: Int?
|
||||
private let selectionBehavior: Backport<Any>.PhotosPickerSelectionBehavior
|
||||
private let encoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy
|
||||
private let library: PHPh otoLibrary
|
||||
private let label: Label
|
||||
let filter: Backport.PHPickerFilter?
|
||||
let maxSelection: Int?
|
||||
let selectionBehavior: Backport.PhotosPickerSelectionBehavior
|
||||
let encoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy
|
||||
let library: PHPhotoLibrary
|
||||
let label: Label
|
||||
|
||||
public var body: some View {
|
||||
Button {
|
||||
|
@ -38,24 +38,11 @@ public extension Backport where Wrapped == Any {
|
|||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
public extension Backport.PhotosPicker where Wrapped == Any {
|
||||
/// Creates a Photos picker that selects a `PhotosPickerItem` from a given photo library.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
/// - photoLibrary: The photo library to choose from.
|
||||
/// - label: The view that describes the action of choosing an item from the photo library.
|
||||
@available(iOS, introduced: 13, deprecated: 14)
|
||||
public extension Backport<Any>.PhotosPicker {
|
||||
init(
|
||||
selection: Binding<Backport<Any>.PhotosPickerItem?>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
matching filter: Backport<Any>.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary = .shared(),
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
@ViewBuilder label: () -> Label
|
||||
) {
|
||||
_selection = .init(
|
||||
|
@ -67,32 +54,20 @@ public extension Backport.PhotosPicker where Wrapped == Any {
|
|||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = photoLibrary
|
||||
self.encoding = .automatic
|
||||
self.library = .shared()
|
||||
self.label = label()
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
public extension Backport.PhotosPicker where Wrapped == Any, Label == Text {
|
||||
/// Creates a Photos picker with its label generated from a localized string key that selects a `PhotosPickerItem`.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - titleKey: A localized string key that describes the purpose of showing the picker.
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
@available(iOS, introduced: 13, deprecated: 14)
|
||||
public extension Backport<Any>.PhotosPicker<Text> {
|
||||
init(
|
||||
_ title: String,
|
||||
selection: Binding<Backport<Any>.PhotosPickerItem?>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
matching filter: Backport<Any>.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary = .shared()
|
||||
_ titleKey: LocalizedStringKey,
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil
|
||||
) {
|
||||
_selection = .init(
|
||||
get: {
|
||||
|
@ -103,16 +78,267 @@ public extension Backport.PhotosPicker where Wrapped == Any, Label == Text {
|
|||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = photoLibrary
|
||||
label = Text(title)
|
||||
self.encoding = .automatic
|
||||
self.library = .shared()
|
||||
self.label = Text(titleKey)
|
||||
}
|
||||
|
||||
init<S>(
|
||||
_ title: S,
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil
|
||||
) where S: StringProtocol {
|
||||
_selection = .init(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = .automatic
|
||||
self.library = .shared()
|
||||
self.label = Text(title)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
public extension Backport<Any>.PhotosPicker {
|
||||
/// Creates a Photos picker that selects a `PhotosPickerItem`.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
/// - label: The view that describes the action of choosing an item from the photo library.
|
||||
init(
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
@ViewBuilder label: () -> Label
|
||||
) {
|
||||
_selection = .init(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = .shared()
|
||||
self.label = label()
|
||||
}
|
||||
|
||||
/// Creates a Photos picker that selects a `PhotosPickerItem` from a given photo library.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
/// - photoLibrary: The photo library to choose from.
|
||||
/// - label: The view that describes the action of choosing an item from the photo library.
|
||||
init(
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary,
|
||||
@ViewBuilder label: () -> Label
|
||||
) {
|
||||
_selection = .init(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = photoLibrary
|
||||
self.label = label()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Single selection
|
||||
|
||||
@available(iOS 14, *)
|
||||
public extension Backport<Any>.PhotosPicker<Text> {
|
||||
/// Creates a Photos picker with its label generated from a localized string key that selects a `PhotosPickerItem`.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - titleKey: A localized string key that describes the purpose of showing the picker.
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
init(
|
||||
_ titleKey: LocalizedStringKey,
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic
|
||||
) {
|
||||
_selection = .init(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = .shared()
|
||||
self.label = Text(titleKey)
|
||||
}
|
||||
|
||||
/// Creates a Photos picker with its label generated from a string that selects a `PhotosPickerItem`.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - title: A string that describes the purpose of showing the picker.
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
init<S>(
|
||||
_ title: S,
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic
|
||||
) where S: StringProtocol {
|
||||
_selection = .init(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = .shared()
|
||||
self.label = Text(title)
|
||||
}
|
||||
|
||||
/// Creates a Photos picker with its label generated from a localized string key that selects a `PhotosPickerItem` from a given photo library.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - titleKey: A localized string key that describes the purpose of showing the picker.
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
/// - photoLibrary: The photo library to choose from.
|
||||
init(
|
||||
_ titleKey: LocalizedStringKey,
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary
|
||||
) {
|
||||
_selection = .init(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = photoLibrary
|
||||
self.label = Text(titleKey)
|
||||
}
|
||||
|
||||
/// Creates a Photos picker with its label generated from a string that selects a `PhotosPickerItem` from a given photo library.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - title: A string that describes the purpose of showing the picker.
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
/// - photoLibrary: The photo library to choose from.
|
||||
init<S>(
|
||||
_ title: S,
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary
|
||||
) where S: StringProtocol {
|
||||
_selection = .init(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
self.filter = filter
|
||||
self.maxSelection = 1
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = photoLibrary
|
||||
self.label = Text(title)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Multiple selection
|
||||
|
||||
@available(iOS 15, *)
|
||||
public extension Backport.PhotosPicker where Wrapped == Any {
|
||||
public extension Backport<Any>.PhotosPicker {
|
||||
/// Creates a Photos picker that selects a collection of `PhotosPickerItem`.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - selection: All items being shown and selected in the Photos picker.
|
||||
/// - maxSelectionCount: The maximum number of items that can be selected. Default is `nil`. Setting it to `nil` means maximum supported by the system.
|
||||
/// - selectionBehavior: The selection behavior of the Photos picker. Default is `.default`.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of selected items. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
/// - label: The view that describes the action of choosing items from the photo library.
|
||||
init(
|
||||
selection: Binding<[Backport.PhotosPickerItem]>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
selectionBehavior: Backport.PhotosPickerSelectionBehavior = .default,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
@ViewBuilder label: () -> Label
|
||||
) {
|
||||
_selection = selection
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
self.selectionBehavior = selectionBehavior
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = .shared()
|
||||
self.label = label()
|
||||
}
|
||||
|
||||
/// Creates a Photos picker that selects a collection of `PhotosPickerItem` from a given photo library.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
|
@ -126,12 +352,12 @@ public extension Backport.PhotosPicker where Wrapped == Any {
|
|||
/// - photoLibrary: The photo library to choose from.
|
||||
/// - label: The view that describes the action of choosing items from the photo library.
|
||||
init(
|
||||
selection: Binding<[Backport<Any>.PhotosPickerItem]>,
|
||||
selection: Binding<[Backport.PhotosPickerItem]>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
selectionBehavior: Backport<Any>.PhotosPickerSelectionBehavior = .default,
|
||||
matching filter: Backport<Any>.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary = .shared(),
|
||||
selectionBehavior: Backport.PhotosPickerSelectionBehavior = .default,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary,
|
||||
@ViewBuilder label: () -> Label
|
||||
) {
|
||||
_selection = selection
|
||||
|
@ -144,45 +370,94 @@ public extension Backport.PhotosPicker where Wrapped == Any {
|
|||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
public extension Backport.PhotosPicker where Wrapped == Any, Label == Text {
|
||||
/// Creates a Photos picker with its label generated from a string that selects a `PhotosPickerItem` from a given photo library.
|
||||
@available(iOS 15, *)
|
||||
public extension Backport<Any>.PhotosPicker<Text> {
|
||||
/// Creates a Photos picker with its label generated from a localized string key that selects a collection of `PhotosPickerItem`.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - titleKey: A localized string key that describes the purpose of showing the picker.
|
||||
/// - selection: All items being shown and selected in the Photos picker.
|
||||
/// - maxSelectionCount: The maximum number of items that can be selected. Default is `nil`. Setting it to `nil` means maximum supported by the system.
|
||||
/// - selectionBehavior: The selection behavior of the Photos picker. Default is `.default`.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of selected items. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
init(
|
||||
_ titleKey: LocalizedStringKey,
|
||||
selection: Binding<[Backport.PhotosPickerItem]>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
selectionBehavior: Backport.PhotosPickerSelectionBehavior = .default,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic
|
||||
) {
|
||||
_selection = selection
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
self.selectionBehavior = selectionBehavior
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = .shared()
|
||||
self.label = Text(titleKey)
|
||||
}
|
||||
|
||||
/// Creates a Photos picker with its label generated from a string that selects a collection of `PhotosPickerItem`.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - title: A string that describes the purpose of showing the picker.
|
||||
/// - selection: The item being shown and selected in the Photos picker.
|
||||
/// - selection: All items being shown and selected in the Photos picker.
|
||||
/// - maxSelectionCount: The maximum number of items that can be selected. Default is `nil`. Setting it to `nil` means maximum supported by the system.
|
||||
/// - selectionBehavior: The selection behavior of the Photos picker. Default is `.default`.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of the selected item. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
/// - photoLibrary: The photo library to choose from.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of selected items. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
init<S>(
|
||||
_ title: S,
|
||||
selection: Binding<Backport<Any>.PhotosPickerItem?>,
|
||||
selection: Binding<[Backport.PhotosPickerItem]>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
matching filter: Backport<Any>.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary = .shared()
|
||||
selectionBehavior: Backport.PhotosPickerSelectionBehavior = .default,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic
|
||||
) where S: StringProtocol {
|
||||
_selection = .init(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
_selection = selection
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
self.selectionBehavior = .default
|
||||
self.selectionBehavior = selectionBehavior
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = photoLibrary
|
||||
self.library = .shared()
|
||||
self.label = Text(title)
|
||||
}
|
||||
|
||||
/// Creates a Photos picker with its label generated from a localized string key that selects a collection of `PhotosPickerItem` from a given photo library.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - titleKey: A localized string key that describes the purpose of showing the picker.
|
||||
/// - selection: All items being shown and selected in the Photos picker.
|
||||
/// - maxSelectionCount: The maximum number of items that can be selected. Default is `nil`. Setting it to `nil` means maximum supported by the system.
|
||||
/// - selectionBehavior: The selection behavior of the Photos picker. Default is `.default`.
|
||||
/// - filter: Types of items that can be shown. Default is `nil`. Setting it to `nil` means all supported types can be shown.
|
||||
/// - preferredItemEncoding: The encoding disambiguation policy of selected items. Default is `.automatic`. Setting it to `.automatic` means the best encoding determined by the system will be used.
|
||||
/// - photoLibrary: The photo library to choose from.
|
||||
init(
|
||||
_ titleKey: LocalizedStringKey,
|
||||
selection: Binding<[Backport.PhotosPickerItem]>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
selectionBehavior: Backport.PhotosPickerSelectionBehavior = .default,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary
|
||||
) {
|
||||
_selection = selection
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
self.selectionBehavior = selectionBehavior
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = photoLibrary
|
||||
self.label = Text(titleKey)
|
||||
}
|
||||
|
||||
@available(iOS 15, *)
|
||||
public extension Backport.PhotosPicker where Wrapped == Any, Label == Text {
|
||||
/// Creates a Photos picker with its label generated from a string that selects a collection of `PhotosPickerItem` from a given photo library.
|
||||
///
|
||||
/// The user explicitly grants access only to items they choose, so photo library access authorization is not needed.
|
||||
|
@ -197,12 +472,12 @@ public extension Backport.PhotosPicker where Wrapped == Any, Label == Text {
|
|||
/// - photoLibrary: The photo library to choose from.
|
||||
init<S>(
|
||||
_ title: S,
|
||||
selection: Binding<[Backport<Any>.PhotosPickerItem]>,
|
||||
selection: Binding<[Backport.PhotosPickerItem]>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
selectionBehavior: Backport<Any>.PhotosPickerSelectionBehavior = .default,
|
||||
matching filter: Backport<Any>.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary = .shared()
|
||||
selectionBehavior: Backport.PhotosPickerSelectionBehavior = .default,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary
|
||||
) where S: StringProtocol {
|
||||
_selection = selection
|
||||
self.filter = filter
|
||||
|
|
|
@ -1,80 +1,113 @@
|
|||
#if os(iOS)
|
||||
import SwiftUI
|
||||
import PhotosUI
|
||||
import CoreServices
|
||||
|
||||
@available(iOS, introduced: 13, deprecated: 16)
|
||||
public extension Backport where Wrapped == Any {
|
||||
/// A filter that restricts which types of assets to show
|
||||
struct PHPickerFilter: Equatable, Hashable {
|
||||
let predicate: NSPredicate
|
||||
internal let predicate: NSPredicate
|
||||
// this enables us to support iOS 13 for images vs videos
|
||||
internal let mediaTypes: [String]
|
||||
|
||||
internal init(mediaTypes: [String]) {
|
||||
self.predicate = .init(value: true)
|
||||
self.mediaTypes = mediaTypes
|
||||
}
|
||||
|
||||
internal init(predicate: NSPredicate) {
|
||||
self.predicate = predicate
|
||||
self.mediaTypes = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
public extension Backport<Any>.PHPickerFilter {
|
||||
/// The filter for images.
|
||||
public static var images: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaType.image]))
|
||||
static var images: Self {
|
||||
if #available(iOS 14, *) {
|
||||
return .init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaType.image]))
|
||||
} else {
|
||||
return .init(mediaTypes: [String(kUTTypeImage)])
|
||||
}
|
||||
}
|
||||
|
||||
/// The filter for videos.
|
||||
public static var videos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaType.video]))
|
||||
static var videos: Self {
|
||||
if #available(iOS 14, *) {
|
||||
return .init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaType.video]))
|
||||
} else {
|
||||
return .init(mediaTypes: [String(kUTTypeMovie)])
|
||||
}
|
||||
}
|
||||
|
||||
/// The filter for live photos.
|
||||
public static var livePhotos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoLive]))
|
||||
static var livePhotos: Self {
|
||||
if #available(iOS 14, *) {
|
||||
return .init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoLive]))
|
||||
} else {
|
||||
return .init(mediaTypes: [String(kUTTypeMovie), String(kUTTypeLivePhoto)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
public extension Backport<Any>.PHPickerFilter {
|
||||
/// The filter for Depth Effect photos.
|
||||
public static var depthEffectPhotos: Self {
|
||||
static var depthEffectPhotos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoDepthEffect]))
|
||||
}
|
||||
|
||||
/// The filter for panorama photos.
|
||||
public static var panoramas: Self {
|
||||
static var panoramas: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoPanorama]))
|
||||
}
|
||||
|
||||
/// The filter for screenshots.
|
||||
public static var screenshots: Self {
|
||||
static var screenshots: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoScreenshot]))
|
||||
}
|
||||
|
||||
/// The filter for Slow-Mo videos.
|
||||
public static var slomoVideos: Self {
|
||||
static var slomoVideos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.videoHighFrameRate]))
|
||||
}
|
||||
|
||||
/// The filter for time-lapse videos.
|
||||
public static var timelapseVideos: Self {
|
||||
static var timelapseVideos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.videoTimelapse]))
|
||||
}
|
||||
|
||||
/// The filter for Cinematic videos.
|
||||
@available(iOS 15.0, *)
|
||||
public static var cinematicVideos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.videoCinematic]))
|
||||
}
|
||||
|
||||
/// Returns a new filter based on the asset playback style.
|
||||
#warning("NEEDS TESTING!")
|
||||
public static func playbackStyle(_ playbackStyle: PHAsset.PlaybackStyle) -> Self {
|
||||
static func playbackStyle(_ playbackStyle: PHAsset.PlaybackStyle) -> Self {
|
||||
.init(predicate: NSPredicate(format: "(playbackStyle & %d) != 0", argumentArray: [playbackStyle.rawValue]))
|
||||
}
|
||||
|
||||
/// Returns a new filter formed by OR-ing the filters in a given array.
|
||||
public static func any(of subfilters: [Self]) -> Self {
|
||||
static func any(of subfilters: [Self]) -> Self {
|
||||
.init(predicate: NSCompoundPredicate(orPredicateWithSubpredicates: subfilters.map { $0.predicate }))
|
||||
}
|
||||
|
||||
/// Returns a new filter formed by AND-ing the filters in a given array.
|
||||
public static func all(of subfilters: [Self]) -> Self {
|
||||
static func all(of subfilters: [Self]) -> Self {
|
||||
.init(predicate: NSCompoundPredicate(andPredicateWithSubpredicates: subfilters.map { $0.predicate }))
|
||||
}
|
||||
|
||||
/// Returns a new filter formed by negating the given filter.
|
||||
public static func not(_ filter: Self) -> Self {
|
||||
static func not(_ filter: Self) -> Self {
|
||||
.init(predicate: NSCompoundPredicate(notPredicateWithSubpredicate: filter.predicate))
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 15.0, *)
|
||||
public extension Backport<Any>.PHPickerFilter {
|
||||
/// The filter for Cinematic videos.
|
||||
static var cinematicVideos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.videoCinematic]))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue