PhotosPicker is now functional iOs 13-15
This commit is contained in:
parent
c4936d438e
commit
1e926bf829
|
@ -2,7 +2,7 @@
|
|||
import SwiftUI
|
||||
import PhotosUI
|
||||
|
||||
@available(iOS, deprecated: 16.0)
|
||||
@available(iOS, introduced: 14, deprecated: 16.0)
|
||||
public extension Backport where Wrapped: View {
|
||||
/// Presents a Photos picker that selects a `PhotosPickerItem` from a given photo library.
|
||||
///
|
||||
|
@ -30,16 +30,13 @@ public extension Backport where Wrapped: View {
|
|||
}
|
||||
)
|
||||
|
||||
return content.sheet(isPresented: isPresented) {
|
||||
PhotosPickerView(
|
||||
selection: binding,
|
||||
filter: filter,
|
||||
maxSelection: 1,
|
||||
selectionBehavior: .default,
|
||||
encoding: preferredItemEncoding,
|
||||
library: photoLibrary
|
||||
)
|
||||
}
|
||||
return photosPicker(
|
||||
isPresented: isPresented,
|
||||
selection: binding,
|
||||
matching: filter,
|
||||
preferredItemEncoding: preferredItemEncoding,
|
||||
photoLibrary: photoLibrary
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
@ -64,16 +61,82 @@ public extension Backport where Wrapped: View {
|
|||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
photoLibrary: PHPhotoLibrary = .shared()
|
||||
) -> some View {
|
||||
content.sheet(isPresented: isPresented) {
|
||||
PhotosPickerView(
|
||||
selection: selection,
|
||||
filter: filter,
|
||||
maxSelection: maxSelectionCount,
|
||||
selectionBehavior: selectionBehavior,
|
||||
encoding: preferredItemEncoding,
|
||||
library: photoLibrary
|
||||
)
|
||||
}
|
||||
content._photoPicker(
|
||||
isPresented: isPresented,
|
||||
selection: selection,
|
||||
filter: filter,
|
||||
maxSelectionCount: maxSelectionCount,
|
||||
selectionBehavior: selectionBehavior,
|
||||
preferredItemEncoding: preferredItemEncoding,
|
||||
library: photoLibrary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS, introduced: 13, deprecated: 14.0)
|
||||
public extension Backport where Wrapped: View {
|
||||
/// Presents 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:
|
||||
/// - isPresented: The binding to whether the Photos picker should be shown.
|
||||
/// - 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.
|
||||
func photosPicker(
|
||||
isPresented: Binding<Bool>,
|
||||
selection: Binding<Backport<Any>.PhotosPickerItem?>,
|
||||
matching filter: Backport<Any>.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic
|
||||
) -> some View {
|
||||
let binding = Binding(
|
||||
get: {
|
||||
[selection.wrappedValue].compactMap { $0 }
|
||||
},
|
||||
set: { newValue in
|
||||
selection.wrappedValue = newValue.first
|
||||
}
|
||||
)
|
||||
|
||||
return content._photoPicker(
|
||||
isPresented: isPresented,
|
||||
selection: binding,
|
||||
filter: nil,
|
||||
maxSelectionCount: 1,
|
||||
selectionBehavior: .default,
|
||||
preferredItemEncoding: preferredItemEncoding,
|
||||
library: .shared()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/// Presents 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.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - isPresented: The binding to whether the Photos picker should be shown.
|
||||
/// - 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.
|
||||
/// - 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.
|
||||
func photosPicker(
|
||||
isPresented: Binding<Bool>,
|
||||
selection: Binding<[Backport<Any>.PhotosPickerItem]>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
matching filter: Backport<Any>.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic
|
||||
) -> some View {
|
||||
content._photoPicker(
|
||||
isPresented: isPresented,
|
||||
selection: selection,
|
||||
filter: filter,
|
||||
maxSelectionCount: maxSelectionCount,
|
||||
selectionBehavior: .default,
|
||||
preferredItemEncoding: preferredItemEncoding,
|
||||
library: .shared()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,19 +25,20 @@ public extension Backport<Any> {
|
|||
} label: {
|
||||
label
|
||||
}
|
||||
.backport.photosPicker(
|
||||
._photoPicker(
|
||||
isPresented: $isPresented,
|
||||
selection: $selection,
|
||||
filter: filter,
|
||||
maxSelectionCount: maxSelection,
|
||||
selectionBehavior: selectionBehavior,
|
||||
matching: filter,
|
||||
preferredItemEncoding: encoding,
|
||||
photoLibrary: library
|
||||
library: library
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS, introduced: 13, deprecated: 16)
|
||||
public extension Backport<Any>.PhotosPicker {
|
||||
/// Creates a Photos picker that selects a `PhotosPickerItem`.
|
||||
///
|
||||
|
@ -69,7 +70,10 @@ public extension Backport<Any>.PhotosPicker {
|
|||
self.library = .shared()
|
||||
self.label = label()
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS, introduced: 14, deprecated: 16)
|
||||
public extension Backport<Any>.PhotosPicker {
|
||||
/// 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.
|
||||
|
@ -80,6 +84,7 @@ public extension Backport<Any>.PhotosPicker {
|
|||
/// - 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 14, *)
|
||||
init(
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
|
@ -106,6 +111,7 @@ public extension Backport<Any>.PhotosPicker {
|
|||
|
||||
// MARK: Single selection
|
||||
|
||||
@available(iOS, introduced: 13, deprecated: 16)
|
||||
public extension Backport<Any>.PhotosPicker<Text> {
|
||||
/// Creates a Photos picker with its label generated from a localized string key that selects a `PhotosPickerItem`.
|
||||
///
|
||||
|
@ -179,6 +185,7 @@ public extension Backport<Any>.PhotosPicker<Text> {
|
|||
/// - 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.
|
||||
@available(iOS 14, *)
|
||||
init(
|
||||
_ titleKey: LocalizedStringKey,
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
|
@ -212,6 +219,7 @@ public extension Backport<Any>.PhotosPicker<Text> {
|
|||
/// - 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.
|
||||
@available(iOS 14, *)
|
||||
init<S>(
|
||||
_ title: S,
|
||||
selection: Binding<Backport.PhotosPickerItem?>,
|
||||
|
@ -236,8 +244,9 @@ public extension Backport<Any>.PhotosPicker<Text> {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: Multiple selection
|
||||
// MARK: Multiple selection (iOS 15+)
|
||||
|
||||
@available(iOS 15, *)
|
||||
public extension Backport<Any>.PhotosPicker {
|
||||
/// Creates a Photos picker that selects a collection of `PhotosPickerItem`.
|
||||
///
|
||||
|
@ -298,6 +307,7 @@ public extension Backport<Any>.PhotosPicker {
|
|||
}
|
||||
}
|
||||
|
||||
@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`.
|
||||
///
|
||||
|
@ -415,4 +425,90 @@ public extension Backport<Any>.PhotosPicker<Text> {
|
|||
self.label = Text(title)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Multiple selection (iOS 13+)
|
||||
|
||||
@available(iOS 13, *)
|
||||
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.
|
||||
/// - 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,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic,
|
||||
@ViewBuilder label: () -> Label
|
||||
) {
|
||||
_selection = selection
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = .shared()
|
||||
self.label = label()
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
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.
|
||||
/// - 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,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic
|
||||
) {
|
||||
_selection = selection
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
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 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: 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.
|
||||
/// - 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<S>(
|
||||
_ title: S,
|
||||
selection: Binding<[Backport.PhotosPickerItem]>,
|
||||
maxSelectionCount: Int? = nil,
|
||||
matching filter: Backport.PHPickerFilter? = nil,
|
||||
preferredItemEncoding: Backport.PhotosPickerItem.EncodingDisambiguationPolicy = .automatic
|
||||
) where S: StringProtocol {
|
||||
_selection = selection
|
||||
self.filter = filter
|
||||
self.maxSelection = maxSelectionCount
|
||||
self.selectionBehavior = .default
|
||||
self.encoding = preferredItemEncoding
|
||||
self.library = .shared()
|
||||
self.label = Text(title)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,7 @@ import SwiftUI
|
|||
import PhotosUI
|
||||
|
||||
@available(iOS, deprecated: 16)
|
||||
public extension Backport where Wrapped == Any {
|
||||
public extension Backport<Any> {
|
||||
/// An item can contain multiple representations. Each representation has a corresponding content type.
|
||||
struct PhotosPickerItem: Equatable, Hashable {
|
||||
/// A policy that decides the encoding to use given a content type, if multiple encodings are available.
|
||||
|
@ -19,10 +19,9 @@ public extension Backport where Wrapped == Any {
|
|||
/// Uses the most compatible encoding if possible, even if transcoding is required.
|
||||
public static let compatible: Self = .init(rawValue: 2)
|
||||
|
||||
@available(iOS, introduced: 14)
|
||||
public var mode: PHPickerConfiguration.AssetRepresentationMode {
|
||||
@available(iOS 14, *)
|
||||
internal var mode: PHPickerConfiguration.AssetRepresentationMode {
|
||||
switch self {
|
||||
case .automatic: return .automatic
|
||||
case .current: return .current
|
||||
case .compatible: return .compatible
|
||||
default: return .automatic
|
||||
|
|
|
@ -6,11 +6,25 @@ 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 {
|
||||
internal let predicate: NSPredicate
|
||||
struct PHPickerFilter {
|
||||
internal let mediaTypes: [CFString]
|
||||
internal let filter: Any?
|
||||
|
||||
internal init(predicate: NSPredicate) {
|
||||
self.predicate = predicate
|
||||
@available(iOS 13, *)
|
||||
internal init(mediaTypes: [CFString]) {
|
||||
self.mediaTypes = mediaTypes
|
||||
self.filter = nil
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
internal init(filter: PhotosUI.PHPickerFilter) {
|
||||
self.filter = filter
|
||||
self.mediaTypes = []
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
var photosFilter: PhotosUI.PHPickerFilter {
|
||||
filter as! PhotosUI.PHPickerFilter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,71 +33,90 @@ public extension Backport where Wrapped == Any {
|
|||
public extension Backport<Any>.PHPickerFilter {
|
||||
/// The filter for images.
|
||||
static var images: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaType.image]))
|
||||
if #available(iOS 14, *) {
|
||||
return .init(filter: .images)
|
||||
} else {
|
||||
return .init(mediaTypes: [kUTTypeImage])
|
||||
}
|
||||
}
|
||||
|
||||
/// The filter for videos.
|
||||
static var videos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaType.video]))
|
||||
if #available(iOS 14, *) {
|
||||
return .init(filter: .videos)
|
||||
} else {
|
||||
return .init(mediaTypes: [kUTTypeMovie])
|
||||
}
|
||||
}
|
||||
|
||||
/// The filter for live photos.
|
||||
static var livePhotos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoLive]))
|
||||
if #available(iOS 14, *) {
|
||||
return .init(filter: .livePhotos)
|
||||
} else {
|
||||
return .init(mediaTypes: [kUTTypeLivePhoto, kUTTypeMovie])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The filter for Depth Effect photos.
|
||||
static var depthEffectPhotos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoDepthEffect]))
|
||||
@available(iOS 14, *)
|
||||
public extension Backport<Any>.PHPickerFilter {
|
||||
/// Returns a new filter formed by AND-ing the filters in a given array.
|
||||
static func any(of subfilters: [Self]) -> Self {
|
||||
.init(filter: .any(of: subfilters.map { $0.photosFilter }))
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 15, *)
|
||||
public extension Backport<Any>.PHPickerFilter {
|
||||
/// The filter for panorama photos.
|
||||
static var panoramas: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoPanorama]))
|
||||
.init(filter: .panoramas)
|
||||
}
|
||||
|
||||
/// The filter for screenshots.
|
||||
static var screenshots: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.photoScreenshot]))
|
||||
.init(filter: .screenshots)
|
||||
}
|
||||
|
||||
/// The filter for Slow-Mo videos.
|
||||
static var slomoVideos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.videoHighFrameRate]))
|
||||
.init(filter: .slomoVideos)
|
||||
}
|
||||
|
||||
/// The filter for time-lapse videos.
|
||||
static var timelapseVideos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.videoTimelapse]))
|
||||
.init(filter: .timelapseVideos)
|
||||
}
|
||||
|
||||
/// Returns a new filter based on the asset playback style.
|
||||
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.
|
||||
static func any(of subfilters: [Self]) -> Self {
|
||||
.init(predicate: NSCompoundPredicate(orPredicateWithSubpredicates: subfilters.map { $0.predicate }))
|
||||
.init(filter: .playbackStyle(playbackStyle))
|
||||
}
|
||||
|
||||
/// Returns a new filter formed by AND-ing the filters in a given array.
|
||||
static func all(of subfilters: [Self]) -> Self {
|
||||
.init(predicate: NSCompoundPredicate(andPredicateWithSubpredicates: subfilters.map { $0.predicate }))
|
||||
.init(filter: .all(of: subfilters.map { $0.photosFilter }))
|
||||
}
|
||||
|
||||
/// Returns a new filter formed by negating the given filter.
|
||||
static func not(_ filter: Self) -> Self {
|
||||
.init(predicate: NSCompoundPredicate(notPredicateWithSubpredicate: filter.predicate))
|
||||
.init(filter: .not(filter.photosFilter))
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 15.0, *)
|
||||
@available(iOS 16, *)
|
||||
public extension Backport<Any>.PHPickerFilter {
|
||||
/// The filter for Depth Effect photos.
|
||||
static var depthEffectPhotos: Self {
|
||||
.init(filter: .depthEffectPhotos)
|
||||
}
|
||||
|
||||
/// The filter for Cinematic videos.
|
||||
static var cinematicVideos: Self {
|
||||
.init(predicate: NSPredicate(format: "(mediaSubtypes & %d) != 0", argumentArray: [PHAssetMediaSubtype.videoCinematic]))
|
||||
.init(filter: .cinematicVideos)
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,239 +1,189 @@
|
|||
//#if os(iOS)
|
||||
//import SwiftUI
|
||||
//import PhotosUI
|
||||
//
|
||||
//internal extension View {
|
||||
// @ViewBuilder
|
||||
// func _photoPicker(
|
||||
// isPresented: Binding<Bool>,
|
||||
// selection: Binding<[Backport<Any>.PhotosPickerItem]>,
|
||||
// filter: Backport<Any>.PHPickerFilter?,
|
||||
// maxSelectionCount: Int?,
|
||||
// selectionBehavior: Backport<Any>.PhotosPickerSelectionBehavior,
|
||||
// preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy,
|
||||
// library: PHPhotoLibrary
|
||||
// ) -> some View {
|
||||
// if #available(iOS 14, *) {
|
||||
// backport.background {
|
||||
// PhotosViewController(
|
||||
// isPresented: isPresented,
|
||||
// selection: selection,
|
||||
// filter: filter,
|
||||
// maxSelectionCount: maxSelectionCount,
|
||||
// selectionBehavior: selectionBehavior,
|
||||
// preferredItemEncoding: preferredItemEncoding,
|
||||
// library: library
|
||||
// )
|
||||
// }
|
||||
// } else {
|
||||
// backport.background {
|
||||
// LegacyPhotosViewController(isPresented: isPresented, selection: selection, filter: filter)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//@available(iOS 14, *)
|
||||
//private struct PhotosViewController: UIViewControllerRepresentable {
|
||||
// @Binding var isPresented: Bool
|
||||
// @Binding var selection: [Backport<Any>.PhotosPickerItem]
|
||||
//
|
||||
// let options: PHFetchOptions
|
||||
//
|
||||
// init(isPresented: Binding<Bool>, selection: Binding<[Backport<Any>.PhotosPickerItem]>, filter: Backport<Any>.PHPickerFilter?, maxSelectionCount: Int?, selectionBehavior: Backport<Any>.PhotosPickerSelectionBehavior, preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy, library: PHPhotoLibrary) {
|
||||
// _isPresented = isPresented
|
||||
// _selection = selection
|
||||
//
|
||||
// options = PHFetchOptions()
|
||||
// options.predicate = filter?.predicate
|
||||
//
|
||||
// if #available(iOS 15, *) {
|
||||
// configuration.selection = selectionBehavior.behaviour
|
||||
// }
|
||||
//
|
||||
// self.configuration = configuration
|
||||
// }
|
||||
//
|
||||
// func makeUIViewController(context: Context) -> Representable {
|
||||
// Representable(
|
||||
// isPresented: $isPresented,
|
||||
// selection: $selection,
|
||||
// configuration: configuration
|
||||
// )
|
||||
// }
|
||||
//
|
||||
//
|
||||
// func updateUIViewController(_ controller: Representable, context: Context) {
|
||||
// controller.selection = $selection
|
||||
// controller.configuration = configuration
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//@available(iOS 14, *)
|
||||
//private extension PhotosViewController {
|
||||
// final class Representable: UIViewController, PHPickerViewControllerDelegate, UIAdaptivePresentationControllerDelegate {
|
||||
// private weak var controller: PHPickerViewController?
|
||||
//
|
||||
// var isPresented: Binding<Bool> {
|
||||
// didSet {
|
||||
// updateControllerLifecycle(
|
||||
// from: oldValue.wrappedValue,
|
||||
// to: isPresented.wrappedValue
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// var selection: Binding<[Backport<Any>.PhotosPickerItem]>
|
||||
// var configuration: PHPickerConfiguration
|
||||
//
|
||||
// init(isPresented: Binding<Bool>, selection: Binding<[Backport<Any>.PhotosPickerItem]>, configuration: PHPickerConfiguration) {
|
||||
// self.isPresented = isPresented
|
||||
// self.selection = selection
|
||||
// self.configuration = configuration
|
||||
//
|
||||
// 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 = PHPickerViewController(configuration: configuration)
|
||||
// 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 picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
||||
// print(results)
|
||||
// dismissController()
|
||||
// }
|
||||
//
|
||||
// func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
||||
// dismissController()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//@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()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//#endif
|
||||
#if os(iOS)
|
||||
import SwiftUI
|
||||
import PhotosUI
|
||||
|
||||
internal extension View {
|
||||
@ViewBuilder
|
||||
func _photoPicker(
|
||||
isPresented: Binding<Bool>,
|
||||
selection: Binding<[Backport<Any>.PhotosPickerItem]>,
|
||||
filter: Backport<Any>.PHPickerFilter?,
|
||||
maxSelectionCount: Int?,
|
||||
selectionBehavior: Backport<Any>.PhotosPickerSelectionBehavior,
|
||||
preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy,
|
||||
library: PHPhotoLibrary
|
||||
) -> some View {
|
||||
if #available(iOS 14, *) {
|
||||
sheet(isPresented: isPresented) {
|
||||
PhotosViewController(
|
||||
isPresented: isPresented,
|
||||
selection: selection,
|
||||
filter: filter,
|
||||
maxSelectionCount: maxSelectionCount,
|
||||
selectionBehavior: selectionBehavior,
|
||||
preferredItemEncoding: preferredItemEncoding,
|
||||
library: library
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
} else {
|
||||
sheet(isPresented: isPresented) {
|
||||
LegacyPhotosViewController(
|
||||
isPresented: isPresented,
|
||||
selection: selection,
|
||||
filter: filter,
|
||||
preferredItemEncoding: preferredItemEncoding
|
||||
)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
private struct PhotosViewController: UIViewControllerRepresentable {
|
||||
@Binding var isPresented: Bool
|
||||
@Binding var selection: [Backport<Any>.PhotosPickerItem]
|
||||
let configuration: PHPickerConfiguration
|
||||
|
||||
init(isPresented: Binding<Bool>, selection: Binding<[Backport<Any>.PhotosPickerItem]>, filter: Backport<Any>.PHPickerFilter?, maxSelectionCount: Int?, selectionBehavior: Backport<Any>.PhotosPickerSelectionBehavior, preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy, library: PHPhotoLibrary) {
|
||||
_isPresented = isPresented
|
||||
_selection = selection
|
||||
|
||||
var configuration = PHPickerConfiguration(photoLibrary: library)
|
||||
configuration.preferredAssetRepresentationMode = preferredItemEncoding.mode
|
||||
configuration.selectionLimit = maxSelectionCount ?? 0
|
||||
configuration.filter = filter?.photosFilter
|
||||
|
||||
if #available(iOS 15, *) {
|
||||
configuration.selection = selectionBehavior.behaviour
|
||||
}
|
||||
|
||||
self.configuration = configuration
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(isPresented: $isPresented, selection: $selection, configuration: configuration)
|
||||
}
|
||||
|
||||
func makeUIViewController(context: Context) -> UIViewController {
|
||||
context.coordinator.controller
|
||||
}
|
||||
|
||||
func updateUIViewController(_ controller: UIViewController, context: Context) {
|
||||
context.coordinator.isPresented = $isPresented
|
||||
context.coordinator.selection = $selection
|
||||
context.coordinator.configuration = configuration
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
private extension PhotosViewController {
|
||||
final class Coordinator: NSObject, PHPickerViewControllerDelegate, UIAdaptivePresentationControllerDelegate {
|
||||
var isPresented: Binding<Bool>
|
||||
var selection: Binding<[Backport<Any>.PhotosPickerItem]>
|
||||
var configuration: PHPickerConfiguration
|
||||
|
||||
lazy var controller: PHPickerViewController = {
|
||||
let controller = PHPickerViewController(configuration: configuration)
|
||||
controller.presentationController?.delegate = self
|
||||
controller.delegate = self
|
||||
return controller
|
||||
}()
|
||||
|
||||
init(isPresented: Binding<Bool>, selection: Binding<[Backport<Any>.PhotosPickerItem]>, configuration: PHPickerConfiguration) {
|
||||
self.isPresented = isPresented
|
||||
self.selection = selection
|
||||
self.configuration = configuration
|
||||
super.init()
|
||||
}
|
||||
|
||||
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
||||
isPresented.wrappedValue = false
|
||||
}
|
||||
|
||||
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
||||
isPresented.wrappedValue = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
private struct LegacyPhotosViewController: UIViewControllerRepresentable {
|
||||
@Binding var isPresented: Bool
|
||||
@Binding var selection: [Backport<Any>.PhotosPickerItem]
|
||||
let filter: Backport<Any>.PHPickerFilter?
|
||||
var preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(isPresented: $isPresented, selection: $selection, filter: filter, preferredItemEncoding: preferredItemEncoding)
|
||||
}
|
||||
|
||||
func makeUIViewController(context: Context) -> UIViewController {
|
||||
context.coordinator.controller
|
||||
}
|
||||
|
||||
|
||||
func updateUIViewController(_ controller: UIViewController, context: Context) {
|
||||
context.coordinator.isPresented = $isPresented
|
||||
context.coordinator.selection = $selection
|
||||
context.coordinator.filter = filter
|
||||
context.coordinator.preferredItemEncoding = preferredItemEncoding
|
||||
}
|
||||
}
|
||||
|
||||
private extension LegacyPhotosViewController {
|
||||
final class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIAdaptivePresentationControllerDelegate {
|
||||
var isPresented: Binding<Bool>
|
||||
var selection: Binding<[Backport<Any>.PhotosPickerItem]>
|
||||
var filter: Backport<Any>.PHPickerFilter?
|
||||
var preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy
|
||||
|
||||
lazy var controller: UIImagePickerController = {
|
||||
let controller = UIImagePickerController()
|
||||
|
||||
if let filter {
|
||||
controller.mediaTypes = filter.mediaTypes.map { String($0) }
|
||||
} 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
|
||||
|
||||
switch preferredItemEncoding {
|
||||
case .compatible:
|
||||
controller.imageExportPreset = .compatible
|
||||
controller.videoExportPreset = AVAssetExportPresetHighestQuality
|
||||
case .current:
|
||||
controller.imageExportPreset = .current
|
||||
controller.videoExportPreset = AVAssetExportPresetPassthrough
|
||||
default:
|
||||
controller.imageExportPreset = .compatible
|
||||
controller.videoExportPreset = AVAssetExportPresetHEVCHighestQuality
|
||||
}
|
||||
|
||||
return controller
|
||||
}()
|
||||
|
||||
init(isPresented: Binding<Bool>, selection: Binding<[Backport<Any>.PhotosPickerItem]>, filter: Backport<Any>.PHPickerFilter?, preferredItemEncoding: Backport<Any>.PhotosPickerItem.EncodingDisambiguationPolicy) {
|
||||
self.isPresented = isPresented
|
||||
self.selection = selection
|
||||
self.filter = filter
|
||||
self.preferredItemEncoding = preferredItemEncoding
|
||||
super.init()
|
||||
}
|
||||
|
||||
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
|
||||
isPresented.wrappedValue = false
|
||||
}
|
||||
|
||||
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
||||
isPresented.wrappedValue = false
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue