⚡ watchOS cache image
This commit is contained in:
		| @@ -182,6 +182,8 @@ | ||||
| /* Begin PBXFileSystemSynchronizedRootGroup section */ | ||||
| 		7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */ = { | ||||
| 			isa = PBXFileSystemSynchronizedRootGroup; | ||||
| 			exceptions = ( | ||||
| 			); | ||||
| 			path = "WatchRunner Watch App"; | ||||
| 			sourceTree = "<group>"; | ||||
| 		}; | ||||
| @@ -669,14 +671,10 @@ | ||||
| 			inputFileListPaths = ( | ||||
| 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", | ||||
| 			); | ||||
| 			inputPaths = ( | ||||
| 			); | ||||
| 			name = "[CP] Copy Pods Resources"; | ||||
| 			outputFileListPaths = ( | ||||
| 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", | ||||
| 			); | ||||
| 			outputPaths = ( | ||||
| 			); | ||||
| 			runOnlyForDeploymentPostprocessing = 0; | ||||
| 			shellPath = /bin/sh; | ||||
| 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; | ||||
| @@ -734,14 +732,10 @@ | ||||
| 			inputFileListPaths = ( | ||||
| 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", | ||||
| 			); | ||||
| 			inputPaths = ( | ||||
| 			); | ||||
| 			name = "[CP] Embed Pods Frameworks"; | ||||
| 			outputFileListPaths = ( | ||||
| 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", | ||||
| 			); | ||||
| 			outputPaths = ( | ||||
| 			); | ||||
| 			runOnlyForDeploymentPostprocessing = 0; | ||||
| 			shellPath = /bin/sh; | ||||
| 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; | ||||
| @@ -770,14 +764,10 @@ | ||||
| 			inputFileListPaths = ( | ||||
| 				"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks-${CONFIGURATION}-input-files.xcfilelist", | ||||
| 			); | ||||
| 			inputPaths = ( | ||||
| 			); | ||||
| 			name = "[CP] Embed Pods Frameworks"; | ||||
| 			outputFileListPaths = ( | ||||
| 				"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks-${CONFIGURATION}-output-files.xcfilelist", | ||||
| 			); | ||||
| 			outputPaths = ( | ||||
| 			); | ||||
| 			runOnlyForDeploymentPostprocessing = 0; | ||||
| 			shellPath = /bin/sh; | ||||
| 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks.sh\"\n"; | ||||
|   | ||||
| @@ -18,15 +18,12 @@ class ImageLoader: ObservableObject { | ||||
|     @Published var errorMessage: String? | ||||
|     @Published var isLoading = false | ||||
|  | ||||
|     private var dataTask: URLSessionDataTask? | ||||
|     private let session: URLSession | ||||
|     private var currentTask: DownloadTask? | ||||
|  | ||||
|     init(session: URLSession = .shared) { | ||||
|         self.session = session | ||||
|     } | ||||
|     init() {} | ||||
|  | ||||
|     deinit { | ||||
|         dataTask?.cancel() | ||||
|         currentTask?.cancel() | ||||
|     } | ||||
|  | ||||
|     func loadImage(from initialUrl: URL, token: String) async { | ||||
| @@ -34,70 +31,67 @@ class ImageLoader: ObservableObject { | ||||
|         errorMessage = nil | ||||
|         image = nil | ||||
|  | ||||
|         do { | ||||
|             // First request with Authorization header | ||||
|             var request = URLRequest(url: initialUrl) | ||||
|             request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization") | ||||
|             request.setValue("SolianWatch/1.0", forHTTPHeaderField: "User-Agent") | ||||
|         // Create request modifier for authorization | ||||
|         let modifier = AnyModifier { request in | ||||
|             var r = request | ||||
|             r.setValue("AtField \(token)", forHTTPHeaderField: "Authorization") | ||||
|             r.setValue("SolianWatch/1.0", forHTTPHeaderField: "User-Agent") | ||||
|             return r | ||||
|         } | ||||
|  | ||||
|             let (data, response) = try await session.data(for: request) | ||||
|         // Use WebP processor as default since the app seems to handle WebP images | ||||
|         let processor = WebPProcessor.default | ||||
|  | ||||
|             if let httpResponse = response as? HTTPURLResponse { | ||||
|                 if httpResponse.statusCode == 302, let redirectLocation = httpResponse.allHeaderFields["Location"] as? String, let redirectUrl = URL(string: redirectLocation) { | ||||
|                     print("[watchOS] Redirecting to: \(redirectUrl)") | ||||
|                     // Second request to the redirected URL (S3 signed URL) without Authorization header | ||||
|                     let (redirectData, _) = try await session.data(from: redirectUrl) | ||||
|                     if let uiImage = UIImage(data: redirectData) { | ||||
|                         self.image = Image(uiImage: uiImage) | ||||
|                         print("[watchOS] Image loaded successfully from redirect URL.") | ||||
|                     } else { | ||||
|                         // Try KingfisherWebP for WebP | ||||
|                         let processor = WebPProcessor.default // Correct usage | ||||
|                         if let kfImage = processor.process(item: .data(redirectData), options: KingfisherParsedOptionsInfo( | ||||
|                             [ | ||||
|         // Use KingfisherManager to retrieve image with caching | ||||
|         currentTask = KingfisherManager.shared.retrieveImage( | ||||
|             with: initialUrl, | ||||
|             options: [ | ||||
|                 .requestModifier(modifier), | ||||
|                 .processor(processor), | ||||
|                                 .loadDiskFileSynchronously, | ||||
|                                 .cacheOriginalImage | ||||
|                 .cacheOriginalImage, // Cache the original image data | ||||
|                 .loadDiskFileSynchronously // Load from disk cache synchronously if available | ||||
|             ] | ||||
|                         )) { | ||||
|                             self.image = Image(uiImage: kfImage) | ||||
|                             print("[watchOS] Image loaded successfully from redirect URL using KingfisherWebP.") | ||||
|                         } else { | ||||
|                             self.errorMessage = "Invalid image data from redirect (could not decode with KingfisherWebP)." | ||||
|                         } | ||||
|                     } | ||||
|                 } else if httpResponse.statusCode == 200 { | ||||
|                     if let uiImage = UIImage(data: data) { | ||||
|                         self.image = Image(uiImage: uiImage) | ||||
|                         print("[watchOS] Image loaded successfully from initial URL.") | ||||
|                     } else { | ||||
|                         // Try KingfisherWebP for WebP | ||||
|                         let processor = WebPProcessor.default // Correct usage | ||||
|                         if let kfImage = processor.process(item: .data(data), options: KingfisherParsedOptionsInfo( | ||||
|                             [ | ||||
|                                 .processor(processor), | ||||
|                                 .loadDiskFileSynchronously, | ||||
|                                 .cacheOriginalImage | ||||
|         ) { [weak self] result in | ||||
|             guard let self = self else { return } | ||||
|  | ||||
|             Task { @MainActor in | ||||
|                 switch result { | ||||
|                 case .success(let value): | ||||
|                     self.image = Image(uiImage: value.image) | ||||
|                     print("[watchOS] Image loaded successfully from \(value.cacheType == .none ? "network" : "cache (\(value.cacheType))").") | ||||
|                     self.isLoading = false | ||||
|                 case .failure(let error): | ||||
|                     // If WebP processor fails (likely due to format), try with default processor | ||||
|                     let defaultProcessor = DefaultImageProcessor.default | ||||
|                     self.currentTask = KingfisherManager.shared.retrieveImage( | ||||
|                         with: initialUrl, | ||||
|                         options: [ | ||||
|                             .requestModifier(modifier), | ||||
|                             .processor(defaultProcessor), | ||||
|                             .cacheOriginalImage, | ||||
|                             .loadDiskFileSynchronously | ||||
|                         ] | ||||
|                         )) { | ||||
|                             self.image = Image(uiImage: kfImage) | ||||
|                             print("[watchOS] Image loaded successfully from initial URL using KingfisherWebP.") | ||||
|                         } else { | ||||
|                             self.errorMessage = "Invalid image data (could not decode with KingfisherWebP)." | ||||
|                     ) { [weak self] fallbackResult in | ||||
|                         guard let self = self else { return } | ||||
|  | ||||
|                         Task { @MainActor in | ||||
|                             switch fallbackResult { | ||||
|                             case .success(let value): | ||||
|                                 self.image = Image(uiImage: value.image) | ||||
|                                 print("[watchOS] Image loaded successfully from \(value.cacheType == .none ? "network" : "cache (\(value.cacheType))") using fallback processor.") | ||||
|                             case .failure(let fallbackError): | ||||
|                                 self.errorMessage = fallbackError.localizedDescription | ||||
|                                 print("[watchOS] Image loading failed: \(fallbackError.localizedDescription)") | ||||
|                             } | ||||
|                             self.isLoading = false | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     self.errorMessage = "HTTP Status Code: \(httpResponse.statusCode)" | ||||
|                 } | ||||
|             } | ||||
|         } catch { | ||||
|             self.errorMessage = error.localizedDescription | ||||
|             print("[watchOS] Image loading failed: \(error.localizedDescription)") | ||||
|         } | ||||
|         isLoading = false | ||||
|     } | ||||
|  | ||||
|     func cancel() { | ||||
|         dataTask?.cancel() | ||||
|         currentTask?.cancel() | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user