diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Example/ImaginaryDemo/ImaginaryDemo.xcodeproj/project.pbxproj b/Example/ImaginaryDemo/ImaginaryDemo.xcodeproj/project.pbxproj index 116f8be..e58179d 100644 --- a/Example/ImaginaryDemo/ImaginaryDemo.xcodeproj/project.pbxproj +++ b/Example/ImaginaryDemo/ImaginaryDemo.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 295D77431C07122700C43B07 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 295D77411C07122700C43B07 /* LaunchScreen.storyboard */; }; 29FC0C2B1C07268100B66E11 /* FeedTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FC0C2A1C07268100B66E11 /* FeedTableViewCell.swift */; }; 938EF94E073488BB7B5AE1F1 /* Pods_ImaginaryDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C16C258DB463D5FFF1DD607 /* Pods_ImaginaryDemo.framework */; }; + F560478A28621EC1008ED0AC /* SwiftUIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F560478928621EC1008ED0AC /* SwiftUIViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -27,6 +28,7 @@ 311B2CD8C66C552F516784F2 /* Pods-ImaginaryDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImaginaryDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-ImaginaryDemo/Pods-ImaginaryDemo.release.xcconfig"; sourceTree = ""; }; 46273A36A5534213CB1EF279 /* Pods-ImaginaryDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImaginaryDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ImaginaryDemo/Pods-ImaginaryDemo.debug.xcconfig"; sourceTree = ""; }; F0A3FBC34DFEEC7A04F84F11 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F560478928621EC1008ED0AC /* SwiftUIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -68,6 +70,7 @@ 295D773F1C07122700C43B07 /* Assets.xcassets */, 295D77411C07122700C43B07 /* LaunchScreen.storyboard */, 295D77441C07122700C43B07 /* Info.plist */, + F560478928621EC1008ED0AC /* SwiftUIViewController.swift */, ); path = ImaginaryDemo; sourceTree = ""; @@ -203,6 +206,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F560478A28621EC1008ED0AC /* SwiftUIViewController.swift in Sources */, 295D773B1C07122700C43B07 /* ViewController.swift in Sources */, 29FC0C2B1C07268100B66E11 /* FeedTableViewCell.swift in Sources */, 295D77391C07122700C43B07 /* AppDelegate.swift in Sources */, @@ -271,7 +275,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -323,7 +327,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -340,7 +344,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = ImaginaryDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = RamonGilabert.ImaginaryDemo; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -354,7 +358,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = ImaginaryDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = RamonGilabert.ImaginaryDemo; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/Example/ImaginaryDemo/ImaginaryDemo/AppDelegate.swift b/Example/ImaginaryDemo/ImaginaryDemo/AppDelegate.swift index f8aec57..b0cf00c 100644 --- a/Example/ImaginaryDemo/ImaginaryDemo/AppDelegate.swift +++ b/Example/ImaginaryDemo/ImaginaryDemo/AppDelegate.swift @@ -2,19 +2,21 @@ import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - - lazy var viewController: ViewController = ViewController() - - var window: UIWindow? - + lazy var viewController: ViewController = ViewController() + lazy var swiftUIViewController: SwiftUIViewController = SwiftUIViewController() + + var window: UIWindow? + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - let navigationController = UINavigationController(rootViewController: viewController) - viewController.title = "Imaginary".uppercased() - - window = UIWindow() - window?.rootViewController = navigationController - window?.makeKeyAndVisible() - - return true - } + let tabVC = UITabBarController() + viewController.tabBarItem.title = "UIKit" + swiftUIViewController.tabBarItem.title = "SwiftUI" + tabVC.setViewControllers([viewController, swiftUIViewController], animated: true) + + window = UIWindow() + window?.rootViewController = tabVC + window?.makeKeyAndVisible() + + return true + } } diff --git a/Example/ImaginaryDemo/ImaginaryDemo/SwiftUIViewController.swift b/Example/ImaginaryDemo/ImaginaryDemo/SwiftUIViewController.swift new file mode 100644 index 0000000..6a4a6cf --- /dev/null +++ b/Example/ImaginaryDemo/ImaginaryDemo/SwiftUIViewController.swift @@ -0,0 +1,52 @@ +// +// SwiftUIViewController.swift +// ImaginaryDemo +// +// Created by Arslan Rafique on 2022-06-21. +// Copyright © 2022 Ramon Gilabert Llop. All rights reserved. +// + +import SwiftUI +import Imaginary + +struct ContentView: SwiftUI.View { + + struct Constants { + static let imageWidth = 500 + static let imageHeight = 500 + static let imageNumber = 400 + } + + var imaginaryArray: [URL] = { + var array = [URL]() + + for i in 0.. 5.3.0) + - Cache (6.0.0) + - Imaginary (5.0.0): + - Cache (~> 6.0.0) DEPENDENCIES: - Imaginary (from `../../`) @@ -15,9 +15,9 @@ EXTERNAL SOURCES: :path: "../../" SPEC CHECKSUMS: - Cache: 48762993ec44e1d93483c4d4a13edd18452326f4 - Imaginary: c3153bbdfadcf1736d736e307d80717b7a8c6040 + Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d + Imaginary: cf5e3a7dd6ab1dcbd47ba8ce5edf2307c4e99eb3 -PODFILE CHECKSUM: 317cccf04e61f3f6f7e8a7e2dbc1ad0f7fa2beee +PODFILE CHECKSUM: f44736d98f74418007761e4973f2c94b08d5db15 -COCOAPODS: 1.9.3 +COCOAPODS: 1.11.3 diff --git a/Imaginary.podspec b/Imaginary.podspec index c5ebb12..335b8bd 100644 --- a/Imaginary.podspec +++ b/Imaginary.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Imaginary" s.summary = "Remote images, as easy as one, two, three." - s.version = "5.0.0" + s.version = "5.0.1" s.homepage = "https://github.com/hyperoslo/Imaginary" s.license = 'MIT' s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" } diff --git a/Imaginary.xcodeproj/project.pbxproj b/Imaginary.xcodeproj/project.pbxproj index 98ecd6a..a7975d0 100644 --- a/Imaginary.xcodeproj/project.pbxproj +++ b/Imaginary.xcodeproj/project.pbxproj @@ -126,6 +126,7 @@ D5DF75911C403D8200BF1AB6 /* Imaginary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Imaginary.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D5DF759E1C403E1000BF1AB6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D5DF75B11C403FBF00BF1AB6 /* Cache.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cache.framework; path = Carthage/Build/iOS/Cache.framework; sourceTree = ""; }; + F560478B2862217B008ED0AC /* SwiftUI */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; path = SwiftUI; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -244,6 +245,7 @@ D2E8C8051F7252C300D2B8EF /* Shared */ = { isa = PBXGroup; children = ( + F560478B2862217B008ED0AC /* SwiftUI */, D2E8C8071F7252C300D2B8EF /* Extensions */, D2E8C8091F7252C300D2B8EF /* Fetcher */, D2E8C80D1F7252C300D2B8EF /* Library */, diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..aece6c2 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Cache", + "repositoryURL": "https://github.com/hyperoslo/Cache", + "state": { + "branch": null, + "revision": "c7f4d633049c3bd649a353bad36f6c17e9df085f", + "version": "6.0.0" + } + } + ] + }, + "version": 1 +} diff --git a/README.md b/README.md index cb7ab01..b9d6bf4 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,16 @@ imageView.setImage(url: imageUrl) { result in `result` is an enum `Result` that let you know if the operation succeeded or failed. The possible error is of `ImaginaryError`. +## SwiftUI + +#### Set image with URL + +Simply pass `URL` to `ImageViewAdapter`. + +```swift +ImageViewAdapter(url: "https://avatars2.githubusercontent.com/u/1340892?v=3&s=200") +``` + ## Advanced ### Passing option @@ -99,7 +109,6 @@ public protocol ImageProcessor { This is how you apply tint color before setting images. - ```swift let option = Option(imagePreprocessor: TintImageProcessor(tintColor: .orange)) imageView.setImage(url: imageUrl, option: option) @@ -142,15 +151,15 @@ These are the buit in displayers. You need to supply the correct displayer for y ### Downloading -`Imaginary` uses `ImageFetcher` under the hood, which has downloader and storage. You can specify your own `ImageDownloader` together with a `modifyRequest` closure, there you can change request body or add more HTTP headers. +`Imaginary` uses `ImageFetcher` under the hood, which has downloader and storage. You can specify your own `ImageDownloader` together with a `modifyRequest` closure, there you can change request body or add more HTTP headers. ```swift var option = Option() option.downloaderMaker = { - return ImageDownloader(modifyRequest: { + return ImageDownloader(modifyRequest: { var request = $0 request.addValue("Bearer 123", forHTTPHeaderField: "Authorization") - return request + return request }) } @@ -220,7 +229,6 @@ multipleFetcher.fetch(urls: imageUrls, each: { result in This is ideal for the new [prefetching mode in UICollectionView](https://developer.apple.com/documentation/uikit/uicollectionview/1771771-prefetchingenabled) - ## Installation **Imaginary** is available through [CocoaPods](http://cocoapods.org). To install diff --git a/Sources/Shared/Fetcher/ImageFetcher.swift b/Sources/Shared/Fetcher/ImageFetcher.swift index 1d9d94f..fcc6e27 100644 --- a/Sources/Shared/Fetcher/ImageFetcher.swift +++ b/Sources/Shared/Fetcher/ImageFetcher.swift @@ -43,16 +43,16 @@ public class ImageFetcher { guard let `self` = self else { return } - + switch result { - case .success(let image): - completion(.value(image)) - case .failure: - if url.isFileURL { - self.fetchFromDisk(url: url, completion: completion) - } else { - self.fetchFromNetwork(url: url, completion: completion) - } + case .value(let image): + completion(.value(image)) + case .error(let error): + if url.isFileURL { + self.fetchFromDisk(url: url, completion: completion) + } else { + self.fetchFromNetwork(url: url, completion: completion) + } } }) } diff --git a/Sources/Shared/SwiftUI/ImageViewAdapter.swift b/Sources/Shared/SwiftUI/ImageViewAdapter.swift new file mode 100644 index 0000000..a735c3e --- /dev/null +++ b/Sources/Shared/SwiftUI/ImageViewAdapter.swift @@ -0,0 +1,27 @@ +// +// ImageViewAdapter.swift +// +// +// Created by Arslan Rafique on 2022-06-21. +// + +import SwiftUI + +@available(iOS 13.0, macOS 10.15, *) +public struct ImageViewAdapter: UIViewRepresentable { + + let url: URL + + public init(url: URL) { + self.url = url + } + + public func makeUIView(context: Context) -> UIView { + let imageView: UIImageView = UIImageView() + imageView.contentMode = .scaleToFill + imageView.setImage(url: self.url) + return imageView + } + + public func updateUIView(_ uiView: UIView, context: Context) {} +}