فهرست منبع

Make it work with brutal extension

onevcat 1 سال پیش
والد
کامیت
790b9b6e75

+ 43 - 3
Demo/Demo/Kingfisher-Demo/Base.lproj/Main.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="peg-r0-mlo">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="peg-r0-mlo">
     <device id="retina5_5" orientation="portrait" appearance="dark"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -491,9 +491,33 @@
                                             <segue destination="wco-eY-gNu" kind="show" id="KCP-ab-diO"/>
                                         </connections>
                                     </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="TIF-8x-GLM">
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="8uq-CX-Fxl">
                                         <rect key="frame" x="0.0" y="710" width="414" height="44"/>
                                         <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="8uq-CX-Fxl" id="I9G-72-N8J">
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Live Photo" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mXz-QJ-f80">
+                                                    <rect key="frame" x="20" y="11.666666666666664" width="80" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="mXz-QJ-f80" firstAttribute="leading" secondItem="I9G-72-N8J" secondAttribute="leading" constant="20" symbolic="YES" id="1BM-Eu-bcs"/>
+                                                <constraint firstItem="mXz-QJ-f80" firstAttribute="centerY" secondItem="I9G-72-N8J" secondAttribute="centerY" id="Fqb-ZQ-J3L"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="mXz-QJ-f80" secondAttribute="trailing" constant="20" symbolic="YES" id="fAH-HG-EXN"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <connections>
+                                            <segue destination="nhf-ZY-JwU" kind="show" id="Srz-py-yg9"/>
+                                        </connections>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="TIF-8x-GLM">
+                                        <rect key="frame" x="0.0" y="754" width="414" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="TIF-8x-GLM" id="ykx-Ds-PkP">
                                             <rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
                                             <autoresizingMask key="autoresizingMask"/>
@@ -992,6 +1016,22 @@
             </objects>
             <point key="canvasLocation" x="2654" y="1061"/>
         </scene>
+        <!--Live Photo View Controller-->
+        <scene sceneID="50O-N8-WQ3">
+            <objects>
+                <viewController id="nhf-ZY-JwU" customClass="LivePhotoViewController" customModule="Kingfisher_Demo" customModuleProvider="target" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="G81-wm-Fnw">
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="12L-DC-epo"/>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    </view>
+                    <navigationItem key="navigationItem" id="bYb-CA-CnJ"/>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="y5S-MW-IuF" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1851" y="2398"/>
+        </scene>
         <!--Asset Image Generator View Controller-->
         <scene sceneID="PCw-9j-oCu">
             <objects>

+ 59 - 0
Demo/Demo/Kingfisher-Demo/ViewControllers/LivePhotoViewController.swift

@@ -0,0 +1,59 @@
+//
+//  LivePhotoViewController.swift
+//  Kingfisher
+//
+//  Created by onevcat on 2024/10/05.
+//
+//  Copyright (c) 2024 Wei Wang <onevcat@gmail.com>
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+
+import UIKit
+import PhotosUI
+import Kingfisher
+
+class LivePhotoViewController: UIViewController {
+    
+    private var livePhotoView: PHLivePhotoView!
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        title = "Live Photo"
+        setupOperationNavigationBar()
+        
+        livePhotoView = PHLivePhotoView()
+        livePhotoView.translatesAutoresizingMaskIntoConstraints = false
+        
+        view.addSubview(livePhotoView)
+        NSLayoutConstraint.activate([
+            livePhotoView.heightAnchor.constraint(equalToConstant: 300),
+            livePhotoView.widthAnchor.constraint(equalToConstant: 300),
+            livePhotoView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
+            livePhotoView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -30)
+        ])
+        
+        let source = LivePhotoSource(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
+            print(result)
+        })
+    }
+}

+ 4 - 0
Demo/Kingfisher-Demo.xcodeproj/project.pbxproj

@@ -54,6 +54,7 @@
 		D12E0CB61C47F9C100AC98AD /* NormalLoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C941C47F91800AC98AD /* NormalLoadingViewController.swift */; };
 		D12EB83E24DD902300329EE1 /* TextAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12EB83D24DD902300329EE1 /* TextAttachmentViewController.swift */; };
 		D12EB84024DDB9E100329EE1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D12EB83F24DDB9E000329EE1 /* LaunchScreen.storyboard */; };
+		D12F67682CB10AE000AB63AB /* LivePhotoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12F67672CB10AD900AB63AB /* LivePhotoViewController.swift */; };
 		D1679A461C4E78B20020FD12 /* Kingfisher-watchOS-Demo Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D1679A451C4E78B20020FD12 /* Kingfisher-watchOS-Demo Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
 		D16CC3D824E03FEA00F1A515 /* AVAssetImageGeneratorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D16CC3D724E03FEA00F1A515 /* AVAssetImageGeneratorViewController.swift */; };
 		D198F41E25EDC11500C53E0D /* LazyVStackDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D198F41D25EDC11500C53E0D /* LazyVStackDemo.swift */; };
@@ -204,6 +205,7 @@
 		D12E0CA11C47F92200AC98AD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		D12EB83D24DD902300329EE1 /* TextAttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextAttachmentViewController.swift; sourceTree = "<group>"; };
 		D12EB83F24DDB9E000329EE1 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
+		D12F67672CB10AD900AB63AB /* LivePhotoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LivePhotoViewController.swift; sourceTree = "<group>"; };
 		D13F49C21BEDA53F00CE335D /* Kingfisher-tvOS-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Kingfisher-tvOS-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 		D16218A4238EAA67004A1C6C /* Kingfisher-Demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Kingfisher-Demo.entitlements"; sourceTree = "<group>"; };
 		D1679A391C4E78B20020FD12 /* Kingfisher-watchOS-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Kingfisher-watchOS-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -386,6 +388,7 @@
 		D1A1CCA921A1936300263AD8 /* ViewControllers */ = {
 			isa = PBXGroup;
 			children = (
+				D12F67672CB10AD900AB63AB /* LivePhotoViewController.swift */,
 				D10AC99721A300C9005F057C /* ProcessorCollectionViewController.swift */,
 				4B1C7A3C21A256E300CE9D31 /* InfinityCollectionViewController.swift */,
 				D1CE1BCF21A1AFA300419000 /* TransitionViewController.swift */,
@@ -731,6 +734,7 @@
 				078DCB512BCFEFB40008114E /* PHPickerResultViewController.swift in Sources */,
 				D1EDF7422C9F01270017FFA5 /* Issue2295View.swift in Sources */,
 				D1A1CCA321A1879600263AD8 /* MainViewController.swift in Sources */,
+				D12F67682CB10AE000AB63AB /* LivePhotoViewController.swift in Sources */,
 				4BC0ED4A29A6EE78003E9CD1 /* Issue2035View.swift in Sources */,
 				D1F06F3721AAEACF000B1C38 /* GIFViewController.swift in Sources */,
 				4B120CA726B91BB70060B092 /* TransitionViewDemo.swift in Sources */,

+ 4 - 2
Sources/General/KingfisherManager+LivePhoto.swift

@@ -91,7 +91,8 @@ extension KingfisherManager {
         let fileURLs = source.resources.map {
             targetCache.cacheFileURLIfOnDisk(
                 forKey: $0.cacheKey,
-                processorIdentifier: checkedOptions.processor.identifier
+                processorIdentifier: checkedOptions.processor.identifier,
+                forcedExtension: $0.referenceFileType.determinedFileExtension(.init())
             )
         }
         if fileURLs.contains(nil) {
@@ -117,7 +118,8 @@ extension KingfisherManager {
                 let cacheKey = resource.cacheKey
                 let existingCachedFileURL = targetCache.cacheFileURLIfOnDisk(
                     forKey: cacheKey,
-                    processorIdentifier: options.processor.identifier
+                    processorIdentifier: options.processor.identifier,
+                    forcedExtension: resource.referenceFileType.determinedFileExtension(.init())
                 )
                 if existingCachedFileURL == nil {
                     return r + [resource]