### Common Use Cases Source: https://github.com/tilltue/tlphotopicker/blob/master/README.md Examples demonstrating common configurations for TLPhotoPicker. ```APIDOC ## Common Use Cases ### Single Photo Selection ```swift picker.configure = .singlePhoto .selectedColor(.systemPurple) ``` ### Video Recording Only ```swift picker.configure = TLPhotosPickerConfigure() .mediaType(.video) .allowPhotograph(false) .allowVideoRecording(true) ``` ### Instagram-style Grid ```swift picker.configure = .compactGrid .maxSelection(10) .selectedColor(UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0)) ``` ### Custom Selection Rules ```swift picker.canSelectAsset = { asset in // Only allow images larger than 300x300 return asset.pixelWidth >= 300 && asset.pixelHeight >= 300 } picker.didExceedMaximumNumberOfSelection = { picker in // Show alert when limit reached } ``` ``` -------------------------------- ### Implement TLPhotosPickerLogDelegate Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/ADVANCED.md Example implementation of the log delegate and assignment to the picker instance. ```swift class ViewController: UIViewController, TLPhotosPickerLogDelegate { func selectedCameraCell(picker: TLPhotosPickerViewController) { print("Camera cell tapped") } func selectedPhoto(picker: TLPhotosPickerViewController, at index: Int) { print("Photo selected at index: \(index)") print("Total selected: \(picker.selectedAssets.count)") } func deselectedPhoto(picker: TLPhotosPickerViewController, at index: Int) { print("Photo deselected at index: \(index)") } func selectedAlbum(picker: TLPhotosPickerViewController, title: String, at index: Int) { print("Album selected: \(title) at index: \(index)") } } // Set log delegate picker.logDelegate = self ``` -------------------------------- ### Use Closure-based Configuration Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/ADVANCED.md An example of initializing the picker and setting custom validation logic using closures. ```swift class ViewController: UIViewController { var selectedAssets = [TLPHAsset]() @IBAction func openPhotoPicker() { let picker = TLPhotosPickerViewController( withTLPHAssets: { [weak self] assets in self?.selectedAssets = assets print("Selected \(assets.count) assets") }, didCancel: { print("Cancelled") } ) picker.canSelectAsset = { [weak self] asset in // Custom validation guard asset.pixelWidth >= 300 else { self?.showAlert("Image too small") return false } return true } picker.didExceedMaximumNumberOfSelection = { [weak self] picker in self?.showAlert("Maximum selection reached") } picker.handleNoAlbumPermissions = { [weak self] picker in self?.showPermissionAlert(for: "Photos") } picker.handleNoCameraPermissions = { [weak self] picker in self?.showPermissionAlert(for: "Camera") } picker.selectedAssets = self.selectedAssets present(picker, animated: true) } } ``` -------------------------------- ### Configure Picker with Builder Pattern Source: https://context7.com/tilltue/tlphotopicker/llms.txt Utilize the fluent builder pattern on TLPhotosPickerConfigure to chain configuration methods for a clean setup. ```swift import TLPhotoPicker class ViewController: UIViewController { @IBAction func openConfiguredPicker(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self // Build configuration with chained methods picker.configure = TLPhotosPickerConfigure() .numberOfColumns(3) // 3 columns in grid .maxSelection(20) // Max 20 items .allowVideo(true) // Include videos .allowLivePhotos(true) // Include Live Photos .spacing(line: 5, interitem: 5) // 5pt spacing .selectedColor(.systemPink) // Pink selection indicator .useCameraButton(true) // Show camera button .allowPhotograph(true) // Allow taking photos .allowVideoRecording(true) // Allow recording videos .recordingQuality(.typeHigh) // High quality recording present(picker, animated: true) } } ``` -------------------------------- ### Helper Method for Common Handlers Source: https://github.com/tilltue/tlphotopicker/blob/master/Example/README.md Extract common setup code for handlers into a private helper method to reduce redundancy. ```swift private func setupCommonHandlers(for picker: TLPhotosPickerViewController) { // Common configuration } ``` -------------------------------- ### Handle Photo Library and Camera Permissions Source: https://context7.com/tilltue/tlphotopicker/llms.txt Implement closures `handleNoAlbumPermissions` and `handleNoCameraPermissions` to guide users to settings when permissions are denied. Ensure `UIKit` and `Photos` are imported. ```swift import TLPhotoPicker import Photos import UIKit class PermissionHandlingViewController: UIViewController, TLPhotosPickerViewControllerDelegate { @IBAction func openPicker(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self // Handle permissions with closures picker.handleNoAlbumPermissions = { [weak self] picker in self?.showPermissionAlert( title: "Photo Library Access Required", message: "Please grant photo library access in Settings to select photos.", picker: picker ) } picker.handleNoCameraPermissions = { [weak self] picker in self?.showPermissionAlert( title: "Camera Access Required", message: "Please grant camera access in Settings to take photos.", picker: picker ) } present(picker, animated: true) } func showPermissionAlert(title: String, message: String, picker: TLPhotosPickerViewController) { let alert = UIAlertController( title: title, message: message, preferredStyle: .alert ) alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) } }) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in picker.dismiss(animated: true) }) picker.present(alert, animated: true) } // Alternative: Using delegate methods func handleNoAlbumPermissions(picker: TLPhotosPickerViewController) { showPermissionAlert( title: "Photo Library Access Required", message: "Please grant access in Settings.", picker: picker ) } func handleNoCameraPermissions(picker: TLPhotosPickerViewController) { showPermissionAlert( title: "Camera Access Required", message: "Please grant access in Settings.", picker: picker ) } func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) { // Handle selected assets } } ``` -------------------------------- ### Instagram-style Picker Configuration Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Example configuration for an Instagram-style picker, setting the number of columns to 3, maximum selection to 10, disabling video, setting a custom selected color, and enabling the camera button. ```swift viewController.configure = TLPhotosPickerConfigure() .numberOfColumns(3) .maxSelection(10) .allowVideo(false) .selectedColor(UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0)) .useCameraButton(true) ``` -------------------------------- ### Large Thumbnails with Single Selection Configuration Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Configure the picker for large thumbnails and single selection mode. This example sets the number of columns to 2, enables single selection, defines spacing, and sets a system blue selected color. ```swift viewController.configure = TLPhotosPickerConfigure() .numberOfColumns(2) .singleSelection(true) .spacing(line: 10, interitem: 10) .selectedColor(.systemBlue) ``` -------------------------------- ### Custom Camera Cell Configuration Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Example for using a custom camera cell, specifying the nib name and bundle. This requires iOS 10.2 or later. ```swift if #available(iOS 10.2, *) { viewController.configure = TLPhotosPickerConfigure() .numberOfColumns(3) .cameraCellNib(name: "CustomCameraCell", bundle: .main) } ``` -------------------------------- ### Add TLPhotoPicker with Swift Package Manager Source: https://github.com/tilltue/tlphotopicker/blob/master/README.md Integrate TLPhotoPicker into your project using Swift Package Manager. This example uses the latest major version. ```swift dependencies: [ .package(url: "https://github.com/tilltue/TLPhotoPicker.git", .upToNextMajor(from: "2.1.0")) ] ``` -------------------------------- ### Apply Configuration Presets Source: https://context7.com/tilltue/tlphotopicker/llms.txt Use pre-built configuration presets like .singlePhoto or .videoOnly to quickly set up common picker behaviors, with the option to chain further customizations. ```swift import TLPhotoPicker class ViewController: UIViewController { @IBAction func singlePhotoSelection(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self // Single photo selection preset picker.configure = .singlePhoto .selectedColor(.systemPurple) present(picker, animated: true) } @IBAction func videoOnlySelection(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self // Video only preset with customization picker.configure = .videoOnly .numberOfColumns(3) .selectedColor(.systemBlue) present(picker, animated: true) } @IBAction func photoOnlySelection(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self // Photo only preset (no videos) picker.configure = .photoOnly .maxSelection(10) present(picker, animated: true) } @IBAction func compactGridSelection(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self // Compact 4-column grid picker.configure = .compactGrid .selectedColor(.systemGreen) present(picker, animated: true) } @IBAction func largeGridSelection(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self // Large 2-column grid picker.configure = .largeGrid .singleSelection(true) present(picker, animated: true) } } ``` -------------------------------- ### Configure TLPhotoPicker Source: https://github.com/tilltue/tlphotopicker/blob/master/Example/README.md Demonstrates traditional, modern builder-style, and preset configuration patterns for the picker. ```swift var configure = TLPhotosPickerConfigure() configure.numberOfColumn = 3 configure.maxSelectedAssets = 20 ``` ```swift viewController.configure = TLPhotosPickerConfigure() .numberOfColumns(3) .maxSelection(20) ``` ```swift viewController.configure = .singlePhoto viewController.configure = .videoOnly viewController.configure = .compactGrid ``` -------------------------------- ### Get Video File Size Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Asynchronously retrieves the file size of a video. The completion handler is called with the size in bytes. ```swift public func videoSize( options: PHVideoRequestOptions? = nil, completion: @escaping (Int) -> Void ) ``` ```swift asset.videoSize { bytes in let mb = Double(bytes) / 1_048_576 print("Video size: \(String(format: \"%.2f\", mb)) MB") } ``` -------------------------------- ### Configuration Updates (Delegate Methods) Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/MIGRATION.md Demonstrates updating the configuration of TLPhotoPicker, showing both the older property assignment method and the newer builder pattern. ```swift ```swift // Before: Property assignments var configure = TLPhotosPickerConfigure() configure.numberOfColumn = 3 configure.singleSelectedMode = true ``` ``` ```swift ```swift // After: Can use builder pattern picker.configure = TLPhotosPickerConfigure() .numberOfColumns(3) .singleSelection(true) // Or continue using property assignments (still supported) var configure = TLPhotosPickerConfigure() configure.numberOfColumn = 3 configure.singleSelectedMode = true ``` ``` -------------------------------- ### Configuration: Grid Layout Options Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Set the number of columns and spacing for the grid layout. ```swift // Number of columns (default: 3) .numberOfColumns(Int) // Spacing between items .spacing(line: CGFloat, interitem: CGFloat) ``` -------------------------------- ### Async/Await for Image Download Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/MIGRATION.md Demonstrates the transition from a callback-based approach to Swift's Async/Await for downloading cloud images. ```swift ```swift selectedAssets.first?.cloudImageDownload( progressBlock: { progress in print("Progress: \(progress)") }, completionBlock: { image in self.imageView.image = image } ) ``` ``` ```swift ```swift Task { if let image = await selectedAssets.first?.fullResolutionImage() { await MainActor.run { self.imageView.image = image } } } ``` ``` -------------------------------- ### Builder Pattern Presets Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Quickly configure TLPhotoPicker using predefined presets for common selection modes and layouts. ```swift // Single photo selection viewController.configure = .singlePhoto // Video only viewController.configure = .videoOnly // Photo only (no videos) viewController.configure = .photoOnly // Compact grid (4 columns) viewController.configure = .compactGrid // Large grid (2 columns) viewController.configure = .largeGrid ``` -------------------------------- ### Install TLPhotoPicker with CocoaPods Source: https://github.com/tilltue/tlphotopicker/blob/master/README.md Use this snippet to add TLPhotoPicker to your iOS project via CocoaPods. Ensure your platform is set to iOS 13.0 or later. ```ruby platform :ios, '13.0' pod "TLPhotoPicker" ``` -------------------------------- ### Get Photo File Size Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Asynchronously retrieves the file size of a photo. The completion handler is called with the size in bytes. Optionally include Live Photo video size. ```swift public func photoSize( options: PHImageRequestOptions? = nil, completion: @escaping (Int) -> Void, livePhotoVideoSize: Bool = false ) ``` ```swift asset.photoSize { bytes in let mb = Double(bytes) / 1_048_576 print("Photo size: \(String(format: \"%.2f\", mb)) MB") } ``` -------------------------------- ### Builder Pattern for Configuration Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/MIGRATION.md Illustrates the use of the new Builder Pattern for configuring TLPhotoPicker, offering a more fluent API compared to manual property assignments. ```swift ```swift var configure = TLPhotosPickerConfigure() configure.numberOfColumn = 3 configure.maxSelectedAssets = 20 configure.allowedVideo = true configure.selectedColor = .systemBlue picker.configure = configure ``` ``` ```swift ```swift picker.configure = TLPhotosPickerConfigure() .numberOfColumns(3) .maxSelection(20) .allowVideo(true) .selectedColor(.systemBlue) ``` ``` ```swift ```swift picker.configure = .singlePhoto picker.configure = .videoOnly .selectedColor(.systemBlue) ``` ``` -------------------------------- ### Get Full Resolution Image Asynchronously Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Retrieves the full-resolution image asynchronously using async/await. Requires iOS 13 or later. Ensure to update the UI on the main thread. ```swift public func fullResolutionImage() async -> UIImage? ``` ```swift Task { if let image = await asset.fullResolutionImage() { await MainActor.run { imageView.image = image } } } ``` -------------------------------- ### Configuration: Camera Options Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Configure camera-related features, including the camera button, photo/video capture, and recording quality. ```swift // Show camera button (default: true) .useCameraButton(Bool) // Allow taking photos (default: true) .allowPhotograph(Bool) // Allow video recording (default: true) .allowVideoRecording(Bool) // Video recording quality .recordingQuality(UIImagePickerController.QualityType) ``` -------------------------------- ### Configure TLPhotoPicker with PHFetchOptions Source: https://context7.com/tilltue/tlphotopicker/llms.txt Utilize PHFetchOptions to precisely control which albums and assets are displayed, allowing filtering by creation date, media type, and specifying collection types. ```swift import TLPhotoPicker import Photos class ViewController: UIViewController { @IBAction func openFilteredPicker(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self var configure = TLPhotosPickerConfigure() // Custom fetch options for assets let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [ NSSortDescriptor(key: "creationDate", ascending: false) ] // Only show images created in the last year let oneYearAgo = Calendar.current.date(byAdding: .year, value: -1, to: Date())! fetchOptions.predicate = NSPredicate( format: "creationDate >= %@ AND mediaType == %d", oneYearAgo as NSDate, PHAssetMediaType.image.rawValue ) configure.fetchOption = fetchOptions // Configure which album types to show configure.fetchCollectionTypes = [ (.smartAlbum, .smartAlbumUserLibrary), // Camera Roll (.smartAlbum, .smartAlbumFavorites), // Favorites (.smartAlbum, .smartAlbumSelfPortraits), // Selfies (.smartAlbum, .smartAlbumPanoramas), // Panoramas (.album, .albumRegular) // User albums ] // Per-collection type options let smartAlbumOptions = PHFetchOptions() smartAlbumOptions.sortDescriptors = [ NSSortDescriptor(key: "creationDate", ascending: false) ] configure.fetchCollectionOption[.assetCollections(.smartAlbum)] = smartAlbumOptions picker.configure = configure present(picker, animated: true) } } ``` -------------------------------- ### Basic Configuration Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Configure TLPhotosPickerViewController with basic settings like the number of columns and maximum selected assets. ```swift let viewController = TLPhotosPickerViewController() var configure = TLPhotosPickerConfigure() configure.numberOfColumn = 3 configure.maxSelectedAssets = 20 viewController.configure = configure ``` -------------------------------- ### Configure Video-Only Picker Source: https://github.com/tilltue/tlphotopicker/blob/master/Example/README.md Configure a picker to only allow video selection and recording, with a specified number of columns. ```swift viewController.configure = .videoOnly .numberOfColumns(3) .allowPhotograph(false) .allowVideoRecording(true) ``` -------------------------------- ### Configure Basic Photo Picker Source: https://github.com/tilltue/tlphotopicker/blob/master/Example/README.md Configure a basic photo picker with a specified number of columns and maximum selection count using the builder pattern. ```swift viewController.configure = TLPhotosPickerConfigure() .numberOfColumns(3) .maxSelection(20) ``` -------------------------------- ### Configuration: Appearance - Custom Icons and Colors Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Customize the appearance of the camera background, camera icon, video icon, and placeholder icon using the property-based API. ```swift var configure = TLPhotosPickerConfigure() configure.cameraBgColor = .systemGray configure.cameraIcon = UIImage(named: "customCamera") configure.videoIcon = UIImage(named: "customVideo") configure.placeholderIcon = UIImage(named: "customPlaceholder") ``` -------------------------------- ### Initialize TLPhotosPickerViewController with Closures Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/ADVANCED.md The available closure-based properties and initializers for configuring the picker without a delegate. ```swift class TLPhotosPickerViewController { init(withPHAssets: (([PHAsset]) -> Void)? = nil, didCancel: (() -> Void)? = nil) init(withTLPHAssets: (([TLPHAsset]) -> Void)? = nil, didCancel: (() -> Void)? = nil) var canSelectAsset: ((PHAsset) -> Bool)? = nil var didExceedMaximumNumberOfSelection: ((TLPhotosPickerViewController) -> Void)? = nil var handleNoAlbumPermissions: ((TLPhotosPickerViewController) -> Void)? = nil var handleNoCameraPermissions: ((TLPhotosPickerViewController) -> Void)? = nil var dismissCompletion: (() -> Void)? = nil } ``` -------------------------------- ### Use Custom Subclass Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/ADVANCED.md Instantiating and presenting the custom picker subclass. ```swift let picker = CustomPhotoPicker() picker.delegate = self present(picker, animated: true) ``` -------------------------------- ### Configure Compact Grid Layout Source: https://github.com/tilltue/tlphotopicker/blob/master/Example/README.md Configure the picker with a compact grid layout, similar to Instagram's, and set the maximum selection count and selected item color. ```swift viewController.configure = .compactGrid .maxSelection(10) .selectedColor(.systemBlue) ``` -------------------------------- ### Implement Live Camera Cell and Register in Picker Source: https://context7.com/tilltue/tlphotopicker/llms.txt Defines a custom cell with AVCaptureSession for live preview and demonstrates how to assign it to the picker configuration. ```swift import TLPhotoPicker import AVFoundation import UIKit class LiveCameraCell: TLPhotoCollectionViewCell { @IBOutlet weak var previewView: UIView! @IBOutlet weak var cameraIconView: UIImageView! private var captureSession: AVCaptureSession? private var previewLayer: AVCaptureVideoPreviewLayer? override func awakeFromNib() { super.awakeFromNib() cameraIconView.image = UIImage(systemName: "camera.fill") } override func willDisplayCell() { super.willDisplayCell() setupCamera() } override func endDisplayingCell() { super.endDisplayingCell() stopCamera() } private func setupCamera() { // Don't setup camera on simulator guard !Platform.isSimulator else { cameraIconView.isHidden = false return } cameraIconView.isHidden = true DispatchQueue.global(qos: .userInitiated).async { [weak self] in let session = AVCaptureSession() session.sessionPreset = .medium guard let device = AVCaptureDevice.default( .builtInWideAngleCamera, for: .video, position: .back ) else { return } guard let input = try? AVCaptureDeviceInput(device: device) else { return } if session.canAddInput(input) { session.addInput(input) } DispatchQueue.main.async { let previewLayer = AVCaptureVideoPreviewLayer(session: session) previewLayer.frame = self?.previewView.bounds ?? .zero previewLayer.videoGravity = .resizeAspectFill self?.previewView.layer.addSublayer(previewLayer) self?.captureSession = session self?.previewLayer = previewLayer DispatchQueue.global(qos: .userInitiated).async { session.startRunning() } } } } private func stopCamera() { captureSession?.stopRunning() previewLayer?.removeFromSuperlayer() captureSession = nil previewLayer = nil } override func layoutSubviews() { super.layoutSubviews() previewLayer?.frame = previewView.bounds } } // Register custom camera cell class LiveCameraViewController: UIViewController { @IBAction func openPicker(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self var configure = TLPhotosPickerConfigure() configure.cameraCellNibSet = (nibName: "LiveCameraCell", bundle: .main) configure.usedCameraButton = true picker.configure = configure present(picker, animated: true) } } ``` -------------------------------- ### Configure TLPhotoPicker with Presets and Builder Pattern Source: https://github.com/tilltue/tlphotopicker/blob/master/README.md Customize the TLPhotoPicker's behavior and appearance using presets like `.singlePhoto` or `.videoOnly`, or by building a custom configuration with the `TLPhotosPickerConfigure` builder pattern. You can also extend presets. ```swift let picker = TLPhotosPickerViewController() // Use presets picker.configure = .singlePhoto picker.configure = .videoOnly picker.configure = .compactGrid // Or build custom configuration picker.configure = TLPhotosPickerConfigure() .numberOfColumns(3) .maxSelection(20) .allowVideo(true) .allowLivePhotos(true) .selectedColor(.systemPink) .useCameraButton(true) // Extend presets picker.configure = .videoOnly .numberOfColumns(4) .selectedColor(.systemBlue) present(picker, animated: true) ``` -------------------------------- ### Update Deployment Target in Xcode Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/MIGRATION.md Illustrates how to change the minimum deployment target for an Xcode project. ```diff ```diff - Deployment Target: iOS 9.1 + Deployment Target: iOS 13.0 ``` ``` -------------------------------- ### Configuration: Localization Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Provide custom titles for albums using a localized dictionary. ```swift // Custom album titles .localizedTitles([String: String]) // Example: .localizedTitles([ "Camera Roll": "모든 사진", "Favorites": "즐겨찾기" ]) ``` -------------------------------- ### Implement CustomDataSources Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/ADVANCED.md Implementation of custom data sources and assignment to the picker. ```swift class CustomDataSources: TLPhotopickerDataSourcesProtocol { func headerReferenceSize() -> CGSize { return CGSize(width: UIScreen.main.bounds.width, height: 50) } func footerReferenceSize() -> CGSize { return .zero } func registerSupplementView(collectionView: UICollectionView) { collectionView.register( CustomHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "CustomHeader" ) } func supplementIdentifier(kind: String) -> String { return "CustomHeader" } func configure(supplement view: UICollectionReusableView, section: (title: String, assets: [TLPHAsset])) { guard let header = view as? CustomHeaderView else { return } header.titleLabel.text = section.title header.countLabel.text = "\(section.assets.count) items" } } // Use custom data sources let picker = TLPhotosPickerViewController() picker.customDataSouces = CustomDataSources() ``` -------------------------------- ### Configure Video Recording Only Source: https://github.com/tilltue/tlphotopicker/blob/master/README.md Configures the picker to restrict media to video and enable video recording. ```swift picker.configure = TLPhotosPickerConfigure() .mediaType(.video) .allowPhotograph(false) .allowVideoRecording(true) ``` -------------------------------- ### Preset: Compact Grid Layout Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Configure the picker to use a compact grid layout with 4 columns. ```swift picker.configure = .compactGrid ``` -------------------------------- ### Initialize TLPhotosPickerViewController Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Initializes the main photo picker view controller. Provides initializers with completion closures for selected assets or cancellation. ```swift public init() public init(withPHAssets: (([PHAsset]) -> Void)?, didCancel: (() -> Void)?) public init(withTLPHAssets: (([TLPHAsset]) -> Void)?, didCancel: (() -> Void)?) ``` -------------------------------- ### Basic TLPhotoPicker Usage Source: https://github.com/tilltue/tlphotopicker/blob/master/README.md Implement this code to present the TLPhotoPicker view controller and handle the selection of assets. Ensure your ViewController conforms to the TLPhotosPickerViewControllerDelegate protocol. ```swift import TLPhotoPicker class ViewController: UIViewController { @IBAction func openPhotoPicker() { let picker = TLPhotosPickerViewController() picker.delegate = self present(picker, animated: true) } } extension ViewController: TLPhotosPickerViewControllerDelegate { func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) { // Handle selected assets for asset in withTLPHAssets { print("Selected: \(asset.originalFileName ?? \"Unknown\")") } } } ``` -------------------------------- ### Configuration: Selection Rules Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Define rules for asset selection, such as maximum number of selections or enabling single selection mode. ```swift // Maximum number of selections (default: unlimited) .maxSelection(Int?) // Enable single selection mode .singleSelection(Bool) ``` -------------------------------- ### Load Assets Source: https://github.com/tilltue/tlphotopicker/blob/master/Example/README.md Provides methods for loading assets synchronously, asynchronously with iCloud support, and using modern Swift concurrency. ```swift if let image = asset.fullResolutionImage { // Use image } ``` ```swift asset.cloudImageDownload( progressBlock: { progress in }, completionBlock: { image in } ) ``` ```swift let image = await asset.fullResolutionImage() ``` -------------------------------- ### Handle Picker Events Source: https://github.com/tilltue/tlphotopicker/blob/master/Example/README.md Shows the difference between using a delegate for complex logic and a closure for simple event handling. ```swift class ViewController: TLPhotosPickerViewControllerDelegate { func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) { // Handle selection } } ``` ```swift picker.didExceedMaximumNumberOfSelection = { picker in // Handle max selection } ``` -------------------------------- ### TLPhotosPickerConfigure Presets Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Static properties providing predefined configuration presets for common use cases like single photo selection, video-only, photo-only, compact grid, and large grid layouts. ```swift public static var singlePhoto: TLPhotosPickerConfigure public static var videoOnly: TLPhotosPickerConfigure public static var photoOnly: TLPhotosPickerConfigure public static var compactGrid: TLPhotosPickerConfigure public static var largeGrid: TLPhotosPickerConfigure ``` -------------------------------- ### Enable Force Touch Preview Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/MIGRATION.md Enable preview on long press using Force Touch or Context Menu API. Defaults to false. ```swift // Enable preview on long press (disabled by default) configure.previewAtForceTouch = true ``` -------------------------------- ### Calculate File Sizes for Photos and Videos Source: https://context7.com/tilltue/tlphotopicker/llms.txt Use this to calculate the total size of selected assets, useful for displaying storage information or enforcing limits. It handles photos, live photos, and videos asynchronously. ```swift import TLPhotoPicker import Photos class FileSizeViewController: UIViewController, TLPhotosPickerViewControllerDelegate { @IBOutlet weak var sizeLabel: UILabel! func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) { calculateTotalSize(for: withTLPHAssets) } func calculateTotalSize(for assets: [TLPHAsset]) { var totalSize = 0 let group = DispatchGroup() for asset in assets { group.enter() switch asset.type { case .photo, .livePhoto: asset.photoSize { size in totalSize += size group.leave() } case .video: asset.videoSize { totalSize += size group.leave() } } } group.notify(queue: .main) { [weak self] in let mbSize = Double(totalSize) / 1_048_576 self?.sizeLabel.text = String(format: "Total size: %.2f MB", mbSize) } } // Get Live Photo video size separately func getLivePhotoVideoSize(_ asset: TLPHAsset) { guard asset.type == .livePhoto else { return } asset.photoSize(livePhotoVideoSize: true) { let mbSize = Double(totalSize) / 1_048_576 print("Live Photo total size (image + video): \(String(format: "%.2f", mbSize)) MB") } } } ``` -------------------------------- ### Handle Permission Denied Cases in TLPhotosPicker Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/ADVANCED.md Implements delegate methods to prompt users to grant permissions via the system settings when access is denied. ```swift extension ViewController: TLPhotosPickerViewControllerDelegate { func handleNoAlbumPermissions(picker: TLPhotosPickerViewController) { let alert = UIAlertController( title: "Photo Library Access Required", message: "Please grant photo library access in Settings to select photos.", preferredStyle: .alert ) alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) } }) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) picker.present(alert, animated: true) } func handleNoCameraPermissions(picker: TLPhotosPickerViewController) { let alert = UIAlertController( title: "Camera Access Required", message: "Please grant camera access in Settings to take photos.", preferredStyle: .alert ) alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) } }) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) picker.present(alert, animated: true) } } ``` -------------------------------- ### Closure-based Initialization Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/ADVANCED.md Initialize TLPhotosPickerViewController using closures for handling selection and cancellation events, offering an alternative to the delegate pattern. ```APIDOC ## Closure-based Initialization ### Description TLPhotosPickerViewController can be initialized and configured using closures, providing a more functional approach to handling callbacks compared to the delegate pattern. ### Available Initializers and Closures ```swift class TLPhotosPickerViewController { // Initializer providing selected assets as TLPHAsset init(withTLPHAssets: (([TLPHAsset]) -> Void)? = nil, didCancel: (() -> Void)? = nil) // Initializer providing selected assets as PHAsset init(withPHAssets: (([PHAsset]) -> Void)? = nil, didCancel: (() -> Void)? = nil) // Closure for custom asset selection validation var canSelectAsset: ((PHAsset) -> Bool)? // Closure called when max selection is exceeded var didExceedMaximumNumberOfSelection: ((TLPhotosPickerViewController) -> Void)? // Closure to handle no album permissions var handleNoAlbumPermissions: ((TLPhotosPickerViewController) -> Void)? // Closure to handle no camera permissions var handleNoCameraPermissions: ((TLPhotosPickerViewController) -> Void)? // Closure called after picker dismissal completes var dismissCompletion: (() -> Void)? } ``` ### Example Usage ```swift class ViewController: UIViewController { var selectedAssets = [TLPHAsset]() @IBAction func openPhotoPicker() { let picker = TLPhotosPickerViewController( withTLPHAssets: { [weak self] assets in self?.selectedAssets = assets print("Selected \(assets.count) assets") }, didCancel: { print("Cancelled") } ) // Custom validation: only allow assets with width >= 300 picker.canSelectAsset = { [weak self] asset in guard asset.pixelWidth >= 300 else { self?.showAlert("Image too small") return false } return true } // Handle exceeding maximum selection picker.didExceedMaximumNumberOfSelection = { [weak self] picker in self?.showAlert("Maximum selection reached") } // Handle permission denied cases picker.handleNoAlbumPermissions = { [weak self] picker in self?.showPermissionAlert(for: "Photos") } picker.handleNoCameraPermissions = { [weak self] picker in self?.showPermissionAlert(for: "Camera") } // Set initially selected assets if any picker.selectedAssets = self.selectedAssets present(picker, animated: true) } } ``` ``` -------------------------------- ### Closure-based TLPhotosPickerViewController Initialization Source: https://context7.com/tilltue/tlphotopicker/llms.txt Use closure callbacks as an alternative to the delegate pattern for simpler use cases. Handles asset selection and cancellation via closures. ```swift import TLPhotoPicker class ViewController: UIViewController { var selectedAssets = [TLPHAsset]() @IBAction func openPhotoPicker(_ sender: UIButton) { let picker = TLPhotosPickerViewController( withTLPHAssets: { [weak self] assets in self?.selectedAssets = assets print("Selected \(assets.count) assets") // Process selected assets for asset in assets { if let phAsset = asset.phAsset { print("Asset ID: \(phAsset.localIdentifier)") print("Dimensions: \(phAsset.pixelWidth)x\(phAsset.pixelHeight)") } } }, didCancel: { print("Selection cancelled") } ) picker.dismissCompletion = { print("Picker fully dismissed") } present(picker, animated: true) } } ``` -------------------------------- ### Configure Instagram-style Grid Source: https://github.com/tilltue/tlphotopicker/blob/master/README.md Sets up a compact grid layout with a maximum selection limit and custom color. ```swift picker.configure = .compactGrid .maxSelection(10) .selectedColor(UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0)) ``` -------------------------------- ### Configuration: Media Types Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Control which media types (video, Live Photos) are allowed for selection. ```swift // Allow video selection (default: true) .allowVideo(Bool) // Allow Live Photos (default: true) .allowLivePhotos(Bool) // Filter by media type .mediaType(PHAssetMediaType?) ``` -------------------------------- ### Update Requirements: iOS and Swift Versions Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/MIGRATION.md Shows the change in minimum deployment targets for iOS and Swift versions between TLPhotoPicker versions. ```diff ```diff - iOS 9.1+ + iOS 13.0+ - Swift 4.2 support via version 1.8.3 + Swift 5.0+ only ``` ``` -------------------------------- ### Basic TLPhotosPickerViewController Usage Source: https://context7.com/tilltue/tlphotopicker/llms.txt Present the photo picker and handle selected assets through the delegate pattern. Implement TLPhotosPickerViewControllerDelegate methods to manage selections and dismissal. ```swift import TLPhotoPicker import Photos class ViewController: UIViewController, TLPhotosPickerViewControllerDelegate { var selectedAssets = [TLPHAsset]() @IBAction func openPhotoPicker(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self picker.selectedAssets = self.selectedAssets // Restore previous selection present(picker, animated: true) } // MARK: - TLPhotosPickerViewControllerDelegate func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) { self.selectedAssets = withTLPHAssets for asset in withTLPHAssets { print("Selected: \(asset.originalFileName ?? \"Unknown\")") print("Type: \(asset.type)") // .photo, .video, .livePhoto print("Order: \(asset.selectedOrder)") } } func photoPickerDidCancel() { print("User cancelled photo selection") } func dismissComplete() { print("Picker dismissed, ready to process assets") } } ``` -------------------------------- ### Configure Date Grouping in TLPhotoPicker Source: https://context7.com/tilltue/tlphotopicker/llms.txt Organize assets by date using groupByFetch options like .month, .year, .week, .day, .hour, or a custom date format. Disables prefetching and may impact performance with large libraries. ```swift import TLPhotoPicker class ViewController: UIViewController { @IBAction func openGroupedPicker(_ sender: UIButton) { let picker = TLPhotosPickerViewController() picker.delegate = self var configure = TLPhotosPickerConfigure() // Group by month configure.groupByFetch = .month // Or use other grouping options: // configure.groupByFetch = .year // configure.groupByFetch = .week // configure.groupByFetch = .day // configure.groupByFetch = .hour // configure.groupByFetch = .custom(dateFormat: "yyyy-MM-dd") // Note: Grouping disables prefetch and may take 1-1.5s for large libraries configure.usedPrefetch = false picker.configure = configure present(picker, animated: true) } } ``` -------------------------------- ### Configure TLPhotosPickerViewController Advanced Options Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Builder methods for advanced configuration, including grouping fetched results and providing localized titles for UI elements. ```swift // Advanced public func groupBy(_ grouping: PHFetchedResultGroupedBy?) -> Self public func localizedTitles(_ titles: [String: String]) -> Self ``` -------------------------------- ### Configure TLPhotosPickerViewController Camera Options Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Builder methods to configure camera-related features, such as enabling the camera button, allowing photos or video recording, and setting recording quality. ```swift // Camera public func useCameraButton(_ use: Bool) -> Self public func allowPhotograph(_ allow: Bool) -> Self public func allowVideoRecording(_ allow: Bool) -> Self public func recordingQuality(_ quality: UIImagePickerController.QualityType) -> Self ``` -------------------------------- ### Implement Delegate Methods Source: https://github.com/tilltue/tlphotopicker/blob/master/README.md Defines the protocol for handling picker events such as dismissal, selection validation, and permission errors. ```swift protocol TLPhotosPickerViewControllerDelegate { func shouldDismissPhotoPicker(withTLPHAssets: [TLPHAsset]) -> Bool func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) func dismissPhotoPicker(withPHAssets: [PHAsset]) func photoPickerDidCancel() func dismissComplete() func canSelectAsset(phAsset: PHAsset) -> Bool func didExceedMaximumNumberOfSelection(picker: TLPhotosPickerViewController) func handleNoAlbumPermissions(picker: TLPhotosPickerViewController) func handleNoCameraPermissions(picker: TLPhotosPickerViewController) } ``` -------------------------------- ### Builder Pattern Extend Presets Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Customize existing presets by chaining additional configuration options. ```swift // Start with a preset and customize viewController.configure = .videoOnly .numberOfColumns(3) .selectedColor(.systemBlue) // Or customize single photo mode viewController.configure = .singlePhoto .selectedColor(.systemPurple) .numberOfColumns(4) ``` -------------------------------- ### Async/Await Image Loading Source: https://github.com/tilltue/tlphotopicker/blob/master/Example/README.md Utilize modern Swift concurrency with Async/Await and TaskGroup to efficiently load full-resolution images from selected assets. ```swift let images = await withTaskGroup(of: UIImage?.self) { group in for asset in selectedAssets { group.addTask { await asset.fullResolutionImage() } } // Collect results... } ``` -------------------------------- ### Enumerations and Helpers Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Configuration types and utility classes for the library. ```APIDOC ## Enumerations ### PHFetchedResultGroupedBy - **year**, **month**, **week**, **day**, **hour**, **custom(dateFormat: String)** ### FetchCollectionType - **assetCollections(PHAssetCollectionType)**, **topLevelUserCollections** ### PopupConfigure - **animation(TimeInterval)** ## Helper Classes ### Platform - **isSimulator** (Bool) - Checks if the current environment is a simulator. ### TLBundle - **bundle() -> Bundle** - Returns the library bundle. - **podBundleImage(named: String) -> UIImage?** - Retrieves an image from the pod bundle. ``` -------------------------------- ### Choose Delegate or Closure Pattern Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/MIGRATION.md Avoid mixing delegate and closure patterns for callbacks. Use one or the other. ```swift // ❌ Bad: Mixing patterns picker.delegate = self picker.dismissCompletion = { /* Won't be called if delegate is set */ } // ✅ Good: Use one pattern // Option 1: Delegate only picker.delegate = self // Option 2: Closures only picker = TLPhotosPickerViewController(withTLPHAssets: { assets in // Handle assets }) ``` -------------------------------- ### Implement Selection Rules via Delegate Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/ADVANCED.md Use the TLPhotosPickerViewControllerDelegate to enforce validation rules for asset selection. ```swift extension ViewController: TLPhotosPickerViewControllerDelegate { func canSelectAsset(phAsset: PHAsset) -> Bool { // Rule 1: Size restriction guard phAsset.pixelWidth >= 100, phAsset.pixelHeight >= 100 else { showAlert("Image must be at least 100x100 pixels") return false } // Rule 2: Aspect ratio restriction let aspectRatio = Double(phAsset.pixelWidth) / Double(phAsset.pixelHeight) guard aspectRatio >= 0.5, aspectRatio <= 2.0 else { showAlert("Invalid aspect ratio") return false } // Rule 3: Video duration limit if phAsset.mediaType == .video { guard phAsset.duration <= 60 else { showAlert("Video must be under 60 seconds") return false } } return true } func didExceedMaximumNumberOfSelection(picker: TLPhotosPickerViewController) { let maxCount = picker.configure.maxSelectedAssets ?? 0 showAlert("You can only select up to \(maxCount) items") } } ``` -------------------------------- ### Builder Pattern Chaining Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Use the fluent builder pattern to chain multiple configuration options for TLPhotoPicker. ```swift viewController.configure = TLPhotosPickerConfigure() .numberOfColumns(3) .maxSelection(20) .allowVideo(true) .allowLivePhotos(true) .spacing(line: 5, interitem: 5) .selectedColor(.systemPink) .useCameraButton(true) ``` -------------------------------- ### Preset: Large Grid Layout Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/CONFIGURATION.md Configure the picker to use a large grid layout with 2 columns. ```swift picker.configure = .largeGrid ``` -------------------------------- ### TLPHAsset File Export Methods Source: https://github.com/tilltue/tlphotopicker/blob/master/Documentation/API.md Methods for exporting media files to temporary locations. ```APIDOC ## TLPHAsset File Export Methods ### `tempCopyMediaFile` Export original media file to temporary location. #### Endpoint `tempCopyMediaFile(videoRequestOptions:imageRequestOptions:livePhotoRequestOptions:exportPreset:convertLivePhotosToJPG:progressBlock:completionBlock:)` #### Parameters - **videoRequestOptions** (PHVideoRequestOptions?) - Options for video export - **imageRequestOptions** (PHImageRequestOptions?) - Options for image export - **livePhotoRequestOptions** (PHLivePhotoRequestOptions?) - Options for Live Photo export - **exportPreset** (String) - Video export quality preset (default: AVAssetExportPresetHighestQuality) - **convertLivePhotosToJPG** (Bool) - If true, export Live Photo as JPG/HEIC still image; otherwise, export as .mov file (default: false) - **progressBlock** ((Double) -> Void)? - Progress callback - **completionBlock** ((URL, String) -> Void) - Completion with file URL and MIME type #### Returns `PHImageRequestID?` - Request ID for cancellation. #### Example ```swift asset.tempCopyMediaFile( convertLivePhotosToJPG: false, progressBlock: { progress in print("Export: \(Int(progress * 100))%") }, completionBlock: { url, mimeType in print("Exported to: \(url)") print("MIME type: \(mimeType)") // Use the file self.uploadFile(at: url) // Clean up temporary file try? FileManager.default.removeItem(at: url) } ) ``` **Live Photo Export:** For complete Live Photo export, call twice: ```swift // Export still image asset.tempCopyMediaFile(convertLivePhotosToJPG: true) { imageURL, _ in // Save image } // Export video component asset.tempCopyMediaFile(convertLivePhotosToJPG: false) { videoURL, _ in // Save video } ``` ### `exportVideoFile` Export video with custom options. #### Endpoint `exportVideoFile(options:outputURL:outputFileType:progressBlock:completionBlock:)` #### Parameters - **options** (PHVideoRequestOptions?) - Video request options - **outputURL** (URL?) - Custom output path (optional) - **outputFileType** (AVFileType) - Export file type (default: .mov) - **progressBlock** ((Double) -> Void)? - Progress callback - **completionBlock** ((URL, String) -> Void) - Completion with URL and MIME type #### Example ```swift let outputURL = FileManager.default.temporaryDirectory .appendingPathComponent("video.mp4") asset.exportVideoFile( outputURL: outputURL, outputFileType: .mp4, progressBlock: { progress in print("Export: \(Int(progress * 100))%") }, completionBlock: { url, mimeType in print("Video exported to: \(url)") } ) ``` ```