Sfoglia il codice sorgente

More documentations

onevcat 1 anno fa
parent
commit
7a6306d2e5

+ 3 - 3
Demo/Demo/Kingfisher-Demo/ViewControllers/LivePhotoViewController.swift

@@ -48,11 +48,11 @@ class LivePhotoViewController: UIViewController {
             livePhotoView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -30)
         ])
         
-        let source = LivePhotoSource(urls: [
+        let urls = [
             "https://github.com/onevcat/Kingfisher-TestImages/raw/refs/heads/master/LivePhotos/live_photo_sample.HEIC",
             "https://github.com/onevcat/Kingfisher-TestImages/raw/refs/heads/master/LivePhotos/live_photo_sample.MOV"
-        ].compactMap(URL.init))
-        livePhotoView.kf.setImage(with: source, completionHandler: { result in
+        ].compactMap(URL.init)
+        livePhotoView.kf.setImage(with: urls, completionHandler: { result in
             switch result {
             case .success(let r):
                 print("Live Photo done. \(r.loadingInfo.cacheType)")

+ 69 - 4
Sources/Extensions/PHLivePhotoView+Kingfisher.swift

@@ -92,18 +92,83 @@ extension KingfisherWrapper where Base: PHLivePhotoView {
         set { setRetainedAssociatedObject(base, &contentModeKey, newValue) }
     }
     
-    /// Sets a live photo to the view with a `LivePhotoSource`.
+    /// Sets a live photo to the view with an array of `URL`.
     ///
     /// - Parameters:
-    ///   - source: The `LivePhotoSource` object defining the live photo resource.
+    ///   - urls: The `URL`s defining the live photo resource. It should contains two URLs, one for the still image and
+    ///     one for the video.
+    ///   - options: An options set to define image setting behaviors. See ``KingfisherOptionsInfo`` for more.
+    ///   - completionHandler: Called when the image setting process finishes.
+    /// - Returns: A task represents the image downloading.
+    ///            The return value will be `nil` if the image is set with a empty source.
+    ///
+    /// - Note: Not all options in ``KingfisherOptionsInfo`` are supported in this method, for example, the live photo
+    /// does not support any custom processors. Different from the extension method for a normal image view on the
+    /// platform, the `placeholder` and `progressBlock` are not supported yet, and will be implemented in the future.
+    /// 
+    /// - Note: To get refined control of the resources, use the ``setImage(with:options:completionHandler:)-1n4p2``
+    /// method with a ``LivePhotoSource`` object.
+    ///
+    /// Sample:
+    /// ```swift
+    /// let urls = [
+    ///   URL(string: "https://example.com/image.heic")!, // imageURL
+    ///   URL(string: "https://example.com/video.mov")!   // videoURL
+    /// ]
+    /// let livePhotoView = PHLivePhotoView()
+    /// livePhotoView.kf.setImage(with: urls) { result in
+    ///   switch result {
+    ///   case .success(let retrieveResult):
+    ///     print("Live photo loaded: \(retrieveResult.livePhoto).")
+    ///     print("Cache type: \(retrieveResult.loadingInfo.cacheType).")
+    ///   case .failure(let error):
+    ///     print("Error: \(error)")
+    /// }
+    /// ```
+    @discardableResult
+    public func setImage(
+        with urls: [URL],
+        // placeholder: KFCrossPlatformImage? = nil, // Not supported yet
+        options: KingfisherOptionsInfo? = nil,
+        // progressBlock: DownloadProgressBlock? = nil, // Not supported yet
+        completionHandler: (@MainActor @Sendable (Result<RetrieveLivePhotoResult, KingfisherError>) -> Void)? = nil
+    ) -> Task<(), Never>? {
+        setImage(
+            with: LivePhotoSource(urls: urls),
+            options: options,
+            completionHandler: completionHandler
+        )
+    }
+    
+    /// Sets a live photo to the view with a ``LivePhotoSource``.
+    ///
+    /// - Parameters:
+    ///   - source: The ``LivePhotoSource`` object defining the live photo resource.
     ///   - options: An options set to define image setting behaviors. See `KingfisherOptionsInfo` for more.
     ///   - completionHandler: Called when the image setting process finishes.
     /// - Returns: A task represents the image downloading.
     ///            The return value will be `nil` if the image is set with a empty source.
     ///
-    /// - Note: Not all options in `KingfisherOptionsInfo` are supported in this method, for example, the live photo
-    /// does not support any custom processors. Different from the extension method for a normal image view on the 
+    /// - Note: Not all options in ``KingfisherOptionsInfo`` are supported in this method, for example, the live photo
+    /// does not support any custom processors. Different from the extension method for a normal image view on the
     /// platform, the `placeholder` and `progressBlock` are not supported yet, and will be implemented in the future.
+    /// 
+    /// Sample:
+    /// ```swift
+    /// let source = LivePhotoSource(urls: [
+    ///   URL(string: "https://example.com/image.heic")!, // imageURL
+    ///   URL(string: "https://example.com/video.mov")!   // videoURL
+    /// ])
+    /// let livePhotoView = PHLivePhotoView()
+    /// livePhotoView.kf.setImage(with: source) { result in 
+    ///   switch result {
+    ///   case .success(let retrieveResult):
+    ///     print("Live photo loaded: \(retrieveResult.livePhoto).")
+    ///     print("Cache type: \(retrieveResult.loadingInfo.cacheType).")
+    ///   case .failure(let error):
+    ///     print("Error: \(error)")
+    /// }
+    /// ```
     @discardableResult
     public func setImage(
         with source: LivePhotoSource?,

+ 82 - 23
Sources/General/ImageSource/LivePhotoSource.swift

@@ -26,6 +26,41 @@
 
 import Foundation
 
+/// A type represents a loadable resource for a Live Photo, which consists of a still image and a video.
+/// 
+/// Kingfisher expects a ``LivePhotoSource`` value to load a Live Photo with its high-level APIs. 
+/// A ``LivePhotoSource`` is typically a collection of two ``LivePhotoResource`` values, one for the still image and 
+/// one for the video.
+public struct LivePhotoSource: Sendable {
+    
+    /// The resources of a Live Photo.
+    public let resources: [LivePhotoResource]
+    
+    /// Creates a Live Photo source with given resources.
+    /// - Parameter resources: The downloadable resource for a Live Photo. It should contain two resources, one for the
+    /// still image and one for the video.
+    public init(resources: [any Resource]) {
+        let livePhotoResources = resources.map { LivePhotoResource(resource: $0) }
+        self.init(livePhotoResources)
+    }
+    
+    /// Creates a Live Photo source with given URLs.
+    /// - Parameter urls: The URLs of the downloadable resources for a Live Photo. It should contain two URLs, one for
+    /// the still image and one for the video.
+    public init(urls: [URL]) {
+        let resources = urls.map { KF.ImageResource(downloadURL: $0) }
+        self.init(resources: resources)
+    }
+    
+    /// Creates a Live Photo source with given resources.
+    /// - Parameter resources: The resources for a Live Photo. It should contain two resources, one for the still image
+    /// and one for the video.
+    public init(_ resources: [LivePhotoResource]) {
+        self.resources = resources
+    }
+}
+
+
 /// A resource type representing a component of a Live Photo, which consists of a still image and a video.
 ///
 /// ``LivePhotoResource`` encapsulates the necessary information to download and cache a single components of a Live
@@ -57,22 +92,65 @@ public struct LivePhotoResource: Sendable {
         }
     }
     
+    /// The data source of a Live Photo resource.
+    /// 
+    /// This is a general ``Source`` type, which can be either a network resource (as ``Source/network(_:)``) or a
+    /// provided resource as ``Source/provider(_:)``.
     public let dataSource: Source
+
+    /// The file type of the resource.
     public let referenceFileType: FileType
     
     var cacheKey: String { dataSource.cacheKey }
     var downloadURL: URL? { dataSource.url }
-    
+        
+    /// Creates a Live Photo resource with given download URL, cache key and file type.
+    /// - Parameters:
+    ///   - downloadURL: The URL to download the resource.
+    ///   - cacheKey: The cache key for the resource. If `nil`, Kingfisher will use the `absoluteString` of the URL as
+    ///     the cache key.
+    ///   - fileType: The file type of the resource. If `nil`, Kingfisher will try to guess the file type from the URL.
+    /// 
+    /// The file type is important for Kingfisher to determine how to handle the downloaded data and store them
+    /// in the cache. Photos framework requires the still image to be in HEIC extension and the video to be in MOV 
+    /// extension. Otherwise, the `PHLivePhoto` class might not be able to recognize the data. If you are not sure about
+    /// the file type, you can leave it as `nil` and Kingfisher will try to guess it from the URL and the downloaded 
+    /// data.
     public init(downloadURL: URL, cacheKey: String? = nil, fileType: FileType? = nil) {
         let resource = KF.ImageResource(downloadURL: downloadURL, cacheKey: cacheKey)
         dataSource = .network(resource)
         referenceFileType = fileType ?? resource.guessedFileType
     }
     
+    /// Creates a Live Photo resource with given resource and file type.
+    /// - Parameters:
+    ///   - resource: The resource to download the data.
+    ///   - fileType: The file type of the resource. If `nil`, Kingfisher will try to guess the file type from the URL.
+    /// 
+    /// The file type is important for Kingfisher to determine how to handle the downloaded data and store them
+    /// in the cache. Photos framework requires the still image to be in HEIC extension and the video to be in MOV 
+    /// extension. Otherwise, the `PHLivePhoto` class might not be able to recognize the data. If you are not sure about
+    /// the file type, you can leave it as `nil` and Kingfisher will try to guess it from the URL and the downloaded 
+    /// data.
     public init(resource: any Resource, fileType: FileType? = nil) {
         self.dataSource = .network(resource)
         referenceFileType = fileType ?? resource.guessedFileType
     }
+    
+    /// Creates a Live Photo resource with given data source and file type.
+    /// - Parameters:
+    ///   - source: The data source of the resource. It can be either a network resource or a provided resource.
+    ///   - fileType: The file type of the resource. If `nil`, Kingfisher will try to guess the file type from the URL.
+    /// 
+    /// The file type is important for Kingfisher to determine how to handle the downloaded data and store them
+    /// in the cache. Photos framework requires the still image to be in HEIC extension and the video to be in MOV 
+    /// extension. Otherwise, the `PHLivePhoto` class might not be able to recognize the data. If you are not sure about
+    /// the file type, you can leave it as `nil` and Kingfisher will try to guess it from the URL and the downloaded 
+    /// data.
+    public init(source: Source, fileType: FileType? = nil) {
+        self.dataSource = source
+        referenceFileType = fileType ?? source.url?.guessedFileType ?? .other("")
+    }
 }
 
 extension LivePhotoResource.FileType {
@@ -88,9 +166,9 @@ extension LivePhotoResource.FileType {
         }
     }
     
-    static let fytpChunk: [UInt8] = [0x66, 0x74, 0x79, 0x70]
-    static let heicChunk: [UInt8] = [0x68, 0x65, 0x69, 0x63]
-    static let qtChunk: [UInt8] = [0x71, 0x74, 0x20, 0x20] // quicktime
+    static let fytpChunk: [UInt8] = [0x66, 0x74, 0x79, 0x70] // fytp (file type box)
+    static let heicChunk: [UInt8] = [0x68, 0x65, 0x69, 0x63] // .heic
+    static let qtChunk: [UInt8] = [0x71, 0x74, 0x20, 0x20] // quicktime, .mov
     
     static func guessedFileExtension(from data: Data) -> String? {
         
@@ -124,22 +202,3 @@ extension Resource {
         }
     }
 }
-
-public struct LivePhotoSource: Sendable {
-    
-    public let resources: [LivePhotoResource]
-    
-    public init(resources: [any Resource]) {
-        let livePhotoResources = resources.map { LivePhotoResource(resource: $0) }
-        self.init(livePhotoResources)
-    }
-    
-    public init(urls: [URL]) {
-        let resources = urls.map { KF.ImageResource(downloadURL: $0) }
-        self.init(resources: resources)
-    }
-    
-    public init(_ resources: [LivePhotoResource]) {
-        self.resources = resources
-    }
-}