From f0499a9974a9dd05b49771e7724a35ac91691cd0 Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Thu, 23 Jun 2016 13:08:07 +0200 Subject: [PATCH 1/4] Organize project --- .swiftlint.yml | 2 +- Imaginary.xcodeproj/project.pbxproj | 136 +++++++++++------- {Source => Sources/Shared}/Data/Capsule.swift | 0 .../NSHTTPURLResponse+Imaginary.swift | 0 .../iOS}/Data/Decompressor.swift | 0 {Source => Sources/iOS}/Data/Fetcher.swift | 0 .../iOS}/Extensions/UIImage+Cachable.swift | 0 .../Extensions/UIImageView+Imaginary.swift | 0 {Source => Sources/iOS}/Imaginary.swift | 0 9 files changed, 89 insertions(+), 49 deletions(-) rename {Source => Sources/Shared}/Data/Capsule.swift (100%) rename {Source => Sources/Shared}/Extensions/NSHTTPURLResponse+Imaginary.swift (100%) rename {Source => Sources/iOS}/Data/Decompressor.swift (100%) rename {Source => Sources/iOS}/Data/Fetcher.swift (100%) rename {Source => Sources/iOS}/Extensions/UIImage+Cachable.swift (100%) rename {Source => Sources/iOS}/Extensions/UIImageView+Imaginary.swift (100%) rename {Source => Sources/iOS}/Imaginary.swift (100%) diff --git a/.swiftlint.yml b/.swiftlint.yml index 59cabaa..9297708 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,5 +1,5 @@ included: # paths to include during linting. `--path` is ignored if present. - - Source + - Sources excluded: # paths to ignore during linting. Takes precedence over `included`. - Carthage - Pods diff --git a/Imaginary.xcodeproj/project.pbxproj b/Imaginary.xcodeproj/project.pbxproj index cab6ace..4fa6994 100644 --- a/Imaginary.xcodeproj/project.pbxproj +++ b/Imaginary.xcodeproj/project.pbxproj @@ -7,26 +7,26 @@ objects = { /* Begin PBXBuildFile section */ - D5DF75AA1C403E1000BF1AB6 /* Capsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DF75A11C403E1000BF1AB6 /* Capsule.swift */; }; - D5DF75AB1C403E1000BF1AB6 /* Decompressor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DF75A21C403E1000BF1AB6 /* Decompressor.swift */; }; - D5DF75AC1C403E1000BF1AB6 /* Fetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DF75A31C403E1000BF1AB6 /* Fetcher.swift */; }; - D5DF75AD1C403E1000BF1AB6 /* NSHTTPURLResponse+Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DF75A51C403E1000BF1AB6 /* NSHTTPURLResponse+Imaginary.swift */; }; - D5DF75AE1C403E1000BF1AB6 /* UIImage+Cachable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DF75A61C403E1000BF1AB6 /* UIImage+Cachable.swift */; }; - D5DF75AF1C403E1000BF1AB6 /* UIImageView+Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DF75A71C403E1000BF1AB6 /* UIImageView+Imaginary.swift */; }; - D5DF75B01C403E1000BF1AB6 /* Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DF75A81C403E1000BF1AB6 /* Imaginary.swift */; }; + BDE8FBDB1D1BFA4F00C5A212 /* Decompressor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBCF1D1BFA4F00C5A212 /* Decompressor.swift */; }; + BDE8FBDC1D1BFA4F00C5A212 /* Fetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD01D1BFA4F00C5A212 /* Fetcher.swift */; }; + BDE8FBDD1D1BFA4F00C5A212 /* UIImage+Cachable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD21D1BFA4F00C5A212 /* UIImage+Cachable.swift */; }; + BDE8FBDE1D1BFA4F00C5A212 /* UIImageView+Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD31D1BFA4F00C5A212 /* UIImageView+Imaginary.swift */; }; + BDE8FBDF1D1BFA4F00C5A212 /* Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD41D1BFA4F00C5A212 /* Imaginary.swift */; }; + BDE8FBE01D1BFA4F00C5A212 /* Capsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD81D1BFA4F00C5A212 /* Capsule.swift */; }; + BDE8FBE11D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBDA1D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift */; }; D5DF75B21C403FBF00BF1AB6 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DF75B11C403FBF00BF1AB6 /* Cache.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + BDE8FBCF1D1BFA4F00C5A212 /* Decompressor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decompressor.swift; sourceTree = ""; }; + BDE8FBD01D1BFA4F00C5A212 /* Fetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetcher.swift; sourceTree = ""; }; + BDE8FBD21D1BFA4F00C5A212 /* UIImage+Cachable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Cachable.swift"; sourceTree = ""; }; + BDE8FBD31D1BFA4F00C5A212 /* UIImageView+Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+Imaginary.swift"; sourceTree = ""; }; + BDE8FBD41D1BFA4F00C5A212 /* Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Imaginary.swift; sourceTree = ""; }; + BDE8FBD81D1BFA4F00C5A212 /* Capsule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Capsule.swift; sourceTree = ""; }; + BDE8FBDA1D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSHTTPURLResponse+Imaginary.swift"; sourceTree = ""; }; 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 = ""; }; - D5DF75A11C403E1000BF1AB6 /* Capsule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Capsule.swift; sourceTree = ""; }; - D5DF75A21C403E1000BF1AB6 /* Decompressor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decompressor.swift; sourceTree = ""; }; - D5DF75A31C403E1000BF1AB6 /* Fetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetcher.swift; sourceTree = ""; }; - D5DF75A51C403E1000BF1AB6 /* NSHTTPURLResponse+Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSHTTPURLResponse+Imaginary.swift"; sourceTree = ""; }; - D5DF75A61C403E1000BF1AB6 /* UIImage+Cachable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Cachable.swift"; sourceTree = ""; }; - D5DF75A71C403E1000BF1AB6 /* UIImageView+Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+Imaginary.swift"; sourceTree = ""; }; - D5DF75A81C403E1000BF1AB6 /* Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Imaginary.swift; sourceTree = ""; }; D5DF75B11C403FBF00BF1AB6 /* Cache.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cache.framework; path = Carthage/Build/iOS/Cache.framework; sourceTree = ""; }; /* End PBXFileReference section */ @@ -42,70 +42,110 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - D5DF75871C403D8200BF1AB6 = { + BDE8FBCC1D1BFA4F00C5A212 /* Sources */ = { isa = PBXGroup; children = ( - D5DF75B11C403FBF00BF1AB6 /* Cache.framework */, - D5DF759C1C403E1000BF1AB6 /* Imaginary */, - D5DF759F1C403E1000BF1AB6 /* Source */, - D5DF75921C403D8200BF1AB6 /* Products */, + BDE8FBCD1D1BFA4F00C5A212 /* iOS */, + BDE8FBD51D1BFA4F00C5A212 /* Mac */, + BDE8FBD61D1BFA4F00C5A212 /* Shared */, ); + path = Sources; sourceTree = ""; }; - D5DF75921C403D8200BF1AB6 /* Products */ = { + BDE8FBCD1D1BFA4F00C5A212 /* iOS */ = { isa = PBXGroup; children = ( - D5DF75911C403D8200BF1AB6 /* Imaginary.framework */, + BDE8FBCE1D1BFA4F00C5A212 /* Data */, + BDE8FBD11D1BFA4F00C5A212 /* Extensions */, + BDE8FBD41D1BFA4F00C5A212 /* Imaginary.swift */, ); - name = Products; + path = iOS; sourceTree = ""; }; - D5DF759C1C403E1000BF1AB6 /* Imaginary */ = { + BDE8FBCE1D1BFA4F00C5A212 /* Data */ = { isa = PBXGroup; children = ( - D5DF759D1C403E1000BF1AB6 /* iOS */, + BDE8FBCF1D1BFA4F00C5A212 /* Decompressor.swift */, + BDE8FBD01D1BFA4F00C5A212 /* Fetcher.swift */, ); - path = Imaginary; + path = Data; sourceTree = ""; }; - D5DF759D1C403E1000BF1AB6 /* iOS */ = { + BDE8FBD11D1BFA4F00C5A212 /* Extensions */ = { isa = PBXGroup; children = ( - D5DF759E1C403E1000BF1AB6 /* Info.plist */, + BDE8FBD21D1BFA4F00C5A212 /* UIImage+Cachable.swift */, + BDE8FBD31D1BFA4F00C5A212 /* UIImageView+Imaginary.swift */, ); - path = iOS; + path = Extensions; + sourceTree = ""; + }; + BDE8FBD51D1BFA4F00C5A212 /* Mac */ = { + isa = PBXGroup; + children = ( + ); + path = Mac; sourceTree = ""; }; - D5DF759F1C403E1000BF1AB6 /* Source */ = { + BDE8FBD61D1BFA4F00C5A212 /* Shared */ = { isa = PBXGroup; children = ( - D5DF75A01C403E1000BF1AB6 /* Data */, - D5DF75A41C403E1000BF1AB6 /* Extensions */, - D5DF75A81C403E1000BF1AB6 /* Imaginary.swift */, + BDE8FBD71D1BFA4F00C5A212 /* Data */, + BDE8FBD91D1BFA4F00C5A212 /* Extensions */, ); - path = Source; + path = Shared; sourceTree = ""; }; - D5DF75A01C403E1000BF1AB6 /* Data */ = { + BDE8FBD71D1BFA4F00C5A212 /* Data */ = { isa = PBXGroup; children = ( - D5DF75A11C403E1000BF1AB6 /* Capsule.swift */, - D5DF75A21C403E1000BF1AB6 /* Decompressor.swift */, - D5DF75A31C403E1000BF1AB6 /* Fetcher.swift */, + BDE8FBD81D1BFA4F00C5A212 /* Capsule.swift */, ); path = Data; sourceTree = ""; }; - D5DF75A41C403E1000BF1AB6 /* Extensions */ = { + BDE8FBD91D1BFA4F00C5A212 /* Extensions */ = { isa = PBXGroup; children = ( - D5DF75A51C403E1000BF1AB6 /* NSHTTPURLResponse+Imaginary.swift */, - D5DF75A61C403E1000BF1AB6 /* UIImage+Cachable.swift */, - D5DF75A71C403E1000BF1AB6 /* UIImageView+Imaginary.swift */, + BDE8FBDA1D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift */, ); path = Extensions; sourceTree = ""; }; + D5DF75871C403D8200BF1AB6 = { + isa = PBXGroup; + children = ( + BDE8FBCC1D1BFA4F00C5A212 /* Sources */, + D5DF75B11C403FBF00BF1AB6 /* Cache.framework */, + D5DF759C1C403E1000BF1AB6 /* Imaginary */, + D5DF75921C403D8200BF1AB6 /* Products */, + ); + sourceTree = ""; + }; + D5DF75921C403D8200BF1AB6 /* Products */ = { + isa = PBXGroup; + children = ( + D5DF75911C403D8200BF1AB6 /* Imaginary.framework */, + ); + name = Products; + sourceTree = ""; + }; + D5DF759C1C403E1000BF1AB6 /* Imaginary */ = { + isa = PBXGroup; + children = ( + D5DF759D1C403E1000BF1AB6 /* iOS */, + ); + path = Imaginary; + sourceTree = ""; + }; + D5DF759D1C403E1000BF1AB6 /* iOS */ = { + isa = PBXGroup; + children = ( + D5DF759E1C403E1000BF1AB6 /* Info.plist */, + ); + path = iOS; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -216,13 +256,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D5DF75AF1C403E1000BF1AB6 /* UIImageView+Imaginary.swift in Sources */, - D5DF75AA1C403E1000BF1AB6 /* Capsule.swift in Sources */, - D5DF75AD1C403E1000BF1AB6 /* NSHTTPURLResponse+Imaginary.swift in Sources */, - D5DF75AB1C403E1000BF1AB6 /* Decompressor.swift in Sources */, - D5DF75AC1C403E1000BF1AB6 /* Fetcher.swift in Sources */, - D5DF75B01C403E1000BF1AB6 /* Imaginary.swift in Sources */, - D5DF75AE1C403E1000BF1AB6 /* UIImage+Cachable.swift in Sources */, + BDE8FBDF1D1BFA4F00C5A212 /* Imaginary.swift in Sources */, + BDE8FBE01D1BFA4F00C5A212 /* Capsule.swift in Sources */, + BDE8FBE11D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift in Sources */, + BDE8FBDB1D1BFA4F00C5A212 /* Decompressor.swift in Sources */, + BDE8FBDD1D1BFA4F00C5A212 /* UIImage+Cachable.swift in Sources */, + BDE8FBDE1D1BFA4F00C5A212 /* UIImageView+Imaginary.swift in Sources */, + BDE8FBDC1D1BFA4F00C5A212 /* Fetcher.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/Data/Capsule.swift b/Sources/Shared/Data/Capsule.swift similarity index 100% rename from Source/Data/Capsule.swift rename to Sources/Shared/Data/Capsule.swift diff --git a/Source/Extensions/NSHTTPURLResponse+Imaginary.swift b/Sources/Shared/Extensions/NSHTTPURLResponse+Imaginary.swift similarity index 100% rename from Source/Extensions/NSHTTPURLResponse+Imaginary.swift rename to Sources/Shared/Extensions/NSHTTPURLResponse+Imaginary.swift diff --git a/Source/Data/Decompressor.swift b/Sources/iOS/Data/Decompressor.swift similarity index 100% rename from Source/Data/Decompressor.swift rename to Sources/iOS/Data/Decompressor.swift diff --git a/Source/Data/Fetcher.swift b/Sources/iOS/Data/Fetcher.swift similarity index 100% rename from Source/Data/Fetcher.swift rename to Sources/iOS/Data/Fetcher.swift diff --git a/Source/Extensions/UIImage+Cachable.swift b/Sources/iOS/Extensions/UIImage+Cachable.swift similarity index 100% rename from Source/Extensions/UIImage+Cachable.swift rename to Sources/iOS/Extensions/UIImage+Cachable.swift diff --git a/Source/Extensions/UIImageView+Imaginary.swift b/Sources/iOS/Extensions/UIImageView+Imaginary.swift similarity index 100% rename from Source/Extensions/UIImageView+Imaginary.swift rename to Sources/iOS/Extensions/UIImageView+Imaginary.swift diff --git a/Source/Imaginary.swift b/Sources/iOS/Imaginary.swift similarity index 100% rename from Source/Imaginary.swift rename to Sources/iOS/Imaginary.swift From dc01c78d4d626ccaab1b59cc71e6c7019f8d5b33 Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Thu, 23 Jun 2016 13:19:12 +0200 Subject: [PATCH 2/4] Setup new framework target for Mac --- Cartfile.resolved | 4 +- Imaginary.podspec | 10 +- Imaginary.xcodeproj/project.pbxproj | 159 ++++++++++++++++++++++++++++ Imaginary/Mac/Info.plist | 28 +++++ 4 files changed, 195 insertions(+), 6 deletions(-) create mode 100644 Imaginary/Mac/Info.plist diff --git a/Cartfile.resolved b/Cartfile.resolved index 83e1b6c..4a3ebb8 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,2 +1,2 @@ -github "krzyzanowskim/CryptoSwift" "0.4.1" -github "hyperoslo/Cache" "36ef82487589ad6c91cfc66308ff0c799512b9d6" +github "krzyzanowskim/CryptoSwift" "0.5.1" +github "hyperoslo/Cache" "d6f0b013cbe9ede4b5fe5a8b615220abce0327d6" diff --git a/Imaginary.podspec b/Imaginary.podspec index a165d0e..0b96798 100644 --- a/Imaginary.podspec +++ b/Imaginary.podspec @@ -8,13 +8,15 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/hyperoslo/Imaginary.git", :tag => s.version.to_s } s.social_media_url = 'https://twitter.com/hyperoslo' - s.requires_arc = true - s.source_files = 'Source/**/*' - s.ios.deployment_target = '8.0' - s.osx.deployment_target = '10.9' + s.osx.deployment_target = '10.10' s.tvos.deployment_target = '9.2' + s.requires_arc = true + s.ios.source_files = 'Sources/{iOS,Shared}/**/*' + s.osx.source_files = 'Sources/{Mac,Shared}/**/*' + s.tvos.source_files = 'Sources/{iOS,Shared}/**/*' + s.frameworks = 'UIKit' s.dependency 'Cache' end diff --git a/Imaginary.xcodeproj/project.pbxproj b/Imaginary.xcodeproj/project.pbxproj index 4fa6994..ada9e22 100644 --- a/Imaginary.xcodeproj/project.pbxproj +++ b/Imaginary.xcodeproj/project.pbxproj @@ -14,6 +14,9 @@ BDE8FBDF1D1BFA4F00C5A212 /* Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD41D1BFA4F00C5A212 /* Imaginary.swift */; }; BDE8FBE01D1BFA4F00C5A212 /* Capsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD81D1BFA4F00C5A212 /* Capsule.swift */; }; BDE8FBE11D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBDA1D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift */; }; + BDE8FBF61D1BFC8D00C5A212 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDE8FBF51D1BFC8D00C5A212 /* Cache.framework */; }; + BDE8FBF71D1BFCF000C5A212 /* Capsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD81D1BFA4F00C5A212 /* Capsule.swift */; }; + BDE8FBF81D1BFCF000C5A212 /* NSHTTPURLResponse+Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBDA1D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift */; }; D5DF75B21C403FBF00BF1AB6 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DF75B11C403FBF00BF1AB6 /* Cache.framework */; }; /* End PBXBuildFile section */ @@ -25,12 +28,23 @@ BDE8FBD41D1BFA4F00C5A212 /* Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Imaginary.swift; sourceTree = ""; }; BDE8FBD81D1BFA4F00C5A212 /* Capsule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Capsule.swift; sourceTree = ""; }; BDE8FBDA1D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSHTTPURLResponse+Imaginary.swift"; sourceTree = ""; }; + BDE8FBE91D1BFB9F00C5A212 /* Imaginary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Imaginary.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BDE8FBF41D1BFC7C00C5A212 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BDE8FBF51D1BFC8D00C5A212 /* Cache.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cache.framework; path = Carthage/Build/Mac/Cache.framework; sourceTree = ""; }; 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + BDE8FBE51D1BFB9F00C5A212 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BDE8FBF61D1BFC8D00C5A212 /* Cache.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D5DF758D1C403D8200BF1AB6 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -112,10 +126,19 @@ path = Extensions; sourceTree = ""; }; + BDE8FBF31D1BFC7C00C5A212 /* Mac */ = { + isa = PBXGroup; + children = ( + BDE8FBF41D1BFC7C00C5A212 /* Info.plist */, + ); + path = Mac; + sourceTree = ""; + }; D5DF75871C403D8200BF1AB6 = { isa = PBXGroup; children = ( BDE8FBCC1D1BFA4F00C5A212 /* Sources */, + BDE8FBF51D1BFC8D00C5A212 /* Cache.framework */, D5DF75B11C403FBF00BF1AB6 /* Cache.framework */, D5DF759C1C403E1000BF1AB6 /* Imaginary */, D5DF75921C403D8200BF1AB6 /* Products */, @@ -126,6 +149,7 @@ isa = PBXGroup; children = ( D5DF75911C403D8200BF1AB6 /* Imaginary.framework */, + BDE8FBE91D1BFB9F00C5A212 /* Imaginary.framework */, ); name = Products; sourceTree = ""; @@ -133,6 +157,7 @@ D5DF759C1C403E1000BF1AB6 /* Imaginary */ = { isa = PBXGroup; children = ( + BDE8FBF31D1BFC7C00C5A212 /* Mac */, D5DF759D1C403E1000BF1AB6 /* iOS */, ); path = Imaginary; @@ -149,6 +174,13 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + BDE8FBE61D1BFB9F00C5A212 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D5DF758E1C403D8200BF1AB6 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -159,6 +191,26 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + BDE8FBE81D1BFB9F00C5A212 /* Imaginary-Mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = BDE8FBEE1D1BFB9F00C5A212 /* Build configuration list for PBXNativeTarget "Imaginary-Mac" */; + buildPhases = ( + BDE8FBE41D1BFB9F00C5A212 /* Sources */, + BDE8FBE51D1BFB9F00C5A212 /* Frameworks */, + BDE8FBE61D1BFB9F00C5A212 /* Headers */, + BDE8FBE71D1BFB9F00C5A212 /* Resources */, + BDE8FBF21D1BFBB300C5A212 /* ShellScript */, + BDE8FBF11D1BFBAB00C5A212 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Imaginary-Mac"; + productName = "Imaginary-Mac"; + productReference = BDE8FBE91D1BFB9F00C5A212 /* Imaginary.framework */; + productType = "com.apple.product-type.framework"; + }; D5DF75901C403D8200BF1AB6 /* Imaginary-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = D5DF75991C403D8200BF1AB6 /* Build configuration list for PBXNativeTarget "Imaginary-iOS" */; @@ -188,6 +240,9 @@ LastUpgradeCheck = 0720; ORGANIZATIONNAME = "Hyper Interaktiv AS"; TargetAttributes = { + BDE8FBE81D1BFB9F00C5A212 = { + CreatedOnToolsVersion = 7.3.1; + }; D5DF75901C403D8200BF1AB6 = { CreatedOnToolsVersion = 7.2; }; @@ -206,11 +261,19 @@ projectRoot = ""; targets = ( D5DF75901C403D8200BF1AB6 /* Imaginary-iOS */, + BDE8FBE81D1BFB9F00C5A212 /* Imaginary-Mac */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + BDE8FBE71D1BFB9F00C5A212 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D5DF758F1C403D8200BF1AB6 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -234,6 +297,33 @@ shellPath = /bin/sh; shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; }; + BDE8FBF11D1BFBAB00C5A212 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; + }; + BDE8FBF21D1BFBB300C5A212 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/Mac/Cache.framework", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; D5DF75B31C403FC700BF1AB6 /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -252,6 +342,15 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + BDE8FBE41D1BFB9F00C5A212 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BDE8FBF71D1BFCF000C5A212 /* Capsule.swift in Sources */, + BDE8FBF81D1BFCF000C5A212 /* NSHTTPURLResponse+Imaginary.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D5DF758C1C403D8200BF1AB6 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -269,6 +368,58 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ + BDE8FBEF1D1BFB9F00C5A212 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/Imaginary/Mac/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.Imaginary-Mac"; + PRODUCT_NAME = Imaginary; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + BDE8FBF01D1BFB9F00C5A212 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = "$(SRCROOT)/Imaginary/Mac/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.Imaginary-Mac"; + PRODUCT_NAME = Imaginary; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Release; + }; D5DF75971C403D8200BF1AB6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -403,6 +554,14 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + BDE8FBEE1D1BFB9F00C5A212 /* Build configuration list for PBXNativeTarget "Imaginary-Mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BDE8FBEF1D1BFB9F00C5A212 /* Debug */, + BDE8FBF01D1BFB9F00C5A212 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; D5DF758B1C403D8200BF1AB6 /* Build configuration list for PBXProject "Imaginary" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Imaginary/Mac/Info.plist b/Imaginary/Mac/Info.plist new file mode 100644 index 0000000..67965e8 --- /dev/null +++ b/Imaginary/Mac/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2016 Hyper Interaktiv AS. All rights reserved. + NSPrincipalClass + + + From ed5d19778587c7e80078661f97529f856a5fab7f Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Thu, 23 Jun 2016 14:11:59 +0200 Subject: [PATCH 3/4] Add initial implementation --- Imaginary.xcodeproj/project.pbxproj | 25 +++++ Sources/Mac/Imaginary.swift | 47 ++++++++++ Sources/Shared/Data/Decompressor.swift | 38 ++++++++ Sources/Shared/Data/Fetcher.swift | 92 +++++++++++++++++++ .../Shared/Extensions/NSImage+CGImage.swift | 16 ++++ .../Shared/Extensions/NSImage+Cachable.swift | 11 +++ Sources/Shared/Extensions/NSImageView.swift | 66 +++++++++++++ 7 files changed, 295 insertions(+) create mode 100644 Sources/Mac/Imaginary.swift create mode 100644 Sources/Shared/Data/Decompressor.swift create mode 100644 Sources/Shared/Data/Fetcher.swift create mode 100644 Sources/Shared/Extensions/NSImage+CGImage.swift create mode 100644 Sources/Shared/Extensions/NSImage+Cachable.swift create mode 100644 Sources/Shared/Extensions/NSImageView.swift diff --git a/Imaginary.xcodeproj/project.pbxproj b/Imaginary.xcodeproj/project.pbxproj index ada9e22..f93cc16 100644 --- a/Imaginary.xcodeproj/project.pbxproj +++ b/Imaginary.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + BD936FA11D1C0861006BB76B /* NSImage+CGImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD936F9F1D1C07F3006BB76B /* NSImage+CGImage.swift */; }; + BD936FA31D1C094C006BB76B /* NSImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD936FA21D1C094C006BB76B /* NSImageView.swift */; }; + BD936FA51D1C096F006BB76B /* Fetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD936FA41D1C096F006BB76B /* Fetcher.swift */; }; BDE8FBDB1D1BFA4F00C5A212 /* Decompressor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBCF1D1BFA4F00C5A212 /* Decompressor.swift */; }; BDE8FBDC1D1BFA4F00C5A212 /* Fetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD01D1BFA4F00C5A212 /* Fetcher.swift */; }; BDE8FBDD1D1BFA4F00C5A212 /* UIImage+Cachable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD21D1BFA4F00C5A212 /* UIImage+Cachable.swift */; }; @@ -17,10 +20,16 @@ BDE8FBF61D1BFC8D00C5A212 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDE8FBF51D1BFC8D00C5A212 /* Cache.framework */; }; BDE8FBF71D1BFCF000C5A212 /* Capsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBD81D1BFA4F00C5A212 /* Capsule.swift */; }; BDE8FBF81D1BFCF000C5A212 /* NSHTTPURLResponse+Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBDA1D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift */; }; + BDE8FBFA1D1BFD4200C5A212 /* Imaginary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBF91D1BFD4200C5A212 /* Imaginary.swift */; }; + BDE8FBFC1D1BFD6A00C5A212 /* NSImage+Cachable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBFB1D1BFD6A00C5A212 /* NSImage+Cachable.swift */; }; + BDE8FBFE1D1BFD9600C5A212 /* Decompressor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE8FBFD1D1BFD9600C5A212 /* Decompressor.swift */; }; D5DF75B21C403FBF00BF1AB6 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DF75B11C403FBF00BF1AB6 /* Cache.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + BD936F9F1D1C07F3006BB76B /* NSImage+CGImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSImage+CGImage.swift"; sourceTree = ""; }; + BD936FA21D1C094C006BB76B /* NSImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSImageView.swift; sourceTree = ""; }; + BD936FA41D1C096F006BB76B /* Fetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetcher.swift; sourceTree = ""; }; BDE8FBCF1D1BFA4F00C5A212 /* Decompressor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decompressor.swift; sourceTree = ""; }; BDE8FBD01D1BFA4F00C5A212 /* Fetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetcher.swift; sourceTree = ""; }; BDE8FBD21D1BFA4F00C5A212 /* UIImage+Cachable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Cachable.swift"; sourceTree = ""; }; @@ -31,6 +40,9 @@ BDE8FBE91D1BFB9F00C5A212 /* Imaginary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Imaginary.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BDE8FBF41D1BFC7C00C5A212 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; BDE8FBF51D1BFC8D00C5A212 /* Cache.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cache.framework; path = Carthage/Build/Mac/Cache.framework; sourceTree = ""; }; + BDE8FBF91D1BFD4200C5A212 /* Imaginary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Imaginary.swift; sourceTree = ""; }; + BDE8FBFB1D1BFD6A00C5A212 /* NSImage+Cachable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSImage+Cachable.swift"; sourceTree = ""; }; + BDE8FBFD1D1BFD9600C5A212 /* Decompressor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decompressor.swift; sourceTree = ""; }; 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 = ""; }; @@ -97,6 +109,7 @@ BDE8FBD51D1BFA4F00C5A212 /* Mac */ = { isa = PBXGroup; children = ( + BDE8FBF91D1BFD4200C5A212 /* Imaginary.swift */, ); path = Mac; sourceTree = ""; @@ -114,6 +127,8 @@ isa = PBXGroup; children = ( BDE8FBD81D1BFA4F00C5A212 /* Capsule.swift */, + BDE8FBFD1D1BFD9600C5A212 /* Decompressor.swift */, + BD936FA41D1C096F006BB76B /* Fetcher.swift */, ); path = Data; sourceTree = ""; @@ -122,6 +137,9 @@ isa = PBXGroup; children = ( BDE8FBDA1D1BFA4F00C5A212 /* NSHTTPURLResponse+Imaginary.swift */, + BDE8FBFB1D1BFD6A00C5A212 /* NSImage+Cachable.swift */, + BD936F9F1D1C07F3006BB76B /* NSImage+CGImage.swift */, + BD936FA21D1C094C006BB76B /* NSImageView.swift */, ); path = Extensions; sourceTree = ""; @@ -347,6 +365,12 @@ buildActionMask = 2147483647; files = ( BDE8FBF71D1BFCF000C5A212 /* Capsule.swift in Sources */, + BD936FA51D1C096F006BB76B /* Fetcher.swift in Sources */, + BD936FA31D1C094C006BB76B /* NSImageView.swift in Sources */, + BDE8FBFE1D1BFD9600C5A212 /* Decompressor.swift in Sources */, + BD936FA11D1C0861006BB76B /* NSImage+CGImage.swift in Sources */, + BDE8FBFA1D1BFD4200C5A212 /* Imaginary.swift in Sources */, + BDE8FBFC1D1BFD6A00C5A212 /* NSImage+Cachable.swift in Sources */, BDE8FBF81D1BFCF000C5A212 /* NSHTTPURLResponse+Imaginary.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -561,6 +585,7 @@ BDE8FBF01D1BFB9F00C5A212 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; D5DF758B1C403D8200BF1AB6 /* Build configuration list for PBXProject "Imaginary" */ = { isa = XCConfigurationList; diff --git a/Sources/Mac/Imaginary.swift b/Sources/Mac/Imaginary.swift new file mode 100644 index 0000000..d5a9705 --- /dev/null +++ b/Sources/Mac/Imaginary.swift @@ -0,0 +1,47 @@ +import Cocoa +import Cache + +public struct Imaginary { + + public static var preConfigure: ((imageView: NSImageView) -> Void)? = { imageView in + imageView.layer?.opacity = 0.0 + } + + public static var transitionClosure: ((imageView: NSImageView, image: NSImage) -> Void) = { imageView, newImage in + guard let oldImage = imageView.image else { + imageView.image = newImage + return + } + + let animation = CABasicAnimation(keyPath: "contents") + animation.duration = 0.25 + animation.fromValue = oldImage.cgImage + animation.toValue = newImage.cgImage + imageView.layer?.addAnimation(animation, forKey: "transitionAnimation") + imageView.image = newImage + } + + public static var postConfigure: ((imageView: NSImageView) -> Void)? = { imageView in + let animation = CABasicAnimation(keyPath: "opacity") + animation.fromValue = imageView.layer?.opacity + animation.toValue = 1.0 + imageView.layer?.addAnimation(animation, forKey: "fadeAnimation") + imageView.layer?.opacity = 1.0 + } +} + +public var imageCache: Cache { + + struct Static { + static let config = Config( + frontKind: .Memory, + backKind: .Disk, + expiry: .Date(NSDate().dateByAddingTimeInterval(60 * 60 * 24 * 3)), + maxSize: 0, + maxObjects: 10) + + static let cache = Cache(name: "Imaginary", config: config) + } + + return Static.cache +} diff --git a/Sources/Shared/Data/Decompressor.swift b/Sources/Shared/Data/Decompressor.swift new file mode 100644 index 0000000..b47855a --- /dev/null +++ b/Sources/Shared/Data/Decompressor.swift @@ -0,0 +1,38 @@ +import Cocoa + +struct Decompressor { + + static func decompress(data: NSData, scale: CGFloat = 1) -> NSImage { + guard let image = NSImage(data: data) else { return NSImage() } + + image.lockFocus() + + var imageRect: CGRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height) + let imageRef = image.CGImageForProposedRect(&imageRect, context: nil, hints: nil) + + if CGImageGetAlphaInfo(imageRef) != .None { return image } + + let colorSpaceRef = CGImageGetColorSpace(imageRef) + let width = CGImageGetWidth(imageRef) + let height = CGImageGetHeight(imageRef) + let bytesPerPixel: Int = 4 + let bytesPerRow: Int = bytesPerPixel * width + let bitsPerComponent: Int = 8 + + let context = CGBitmapContextCreate(nil, + width, + height, + bitsPerComponent, + bytesPerRow, + colorSpaceRef, + CGBitmapInfo.ByteOrderDefault.rawValue) + CGContextDrawImage(context, CGRectMake(0, 0, CGFloat(width), CGFloat(height)), imageRef) + + guard let imageRefWithoutAlpha = CGBitmapContextCreateImage(context) else { + return NSImage() + } + let blendedImage = NSImage(CGImage: imageRefWithoutAlpha, size: NSSize(width: CGFloat(width), height: CGFloat(height))) + + return blendedImage + } +} diff --git a/Sources/Shared/Data/Fetcher.swift b/Sources/Shared/Data/Fetcher.swift new file mode 100644 index 0000000..38806e7 --- /dev/null +++ b/Sources/Shared/Data/Fetcher.swift @@ -0,0 +1,92 @@ +import Cocoa +import Foundation + +class Fetcher { + + enum Result { + case Success(NSImage) + case Failure(ErrorType) + } + + enum Error: ErrorType { + case InvalidResponse + case InvalidStatusCode + case InvalidData + case InvalidContentLength + case ConversionError + } + + let URL: NSURL + var task: NSURLSessionDataTask? + var active = false + + var session: NSURLSession { + return NSURLSession.sharedSession() + } + + // MARK: - Initialization + + init(URL: NSURL) { + self.URL = URL + } + + // MARK: - Fetching + + func start(completion: (result: Result) -> Void) { + active = true + + dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) { [weak self] in + guard let weakSelf = self where weakSelf.active else { return } + + weakSelf.task = weakSelf.session.dataTaskWithURL(weakSelf.URL) { + [weak self] data, response, error -> Void in + + guard let weakSelf = self where weakSelf.active else { return } + + if let error = error { + weakSelf.complete { completion(result: .Failure(error)) } + return + } + + guard let httpResponse = response as? NSHTTPURLResponse else { + weakSelf.complete { completion(result: .Failure(Error.InvalidResponse)) } + return + } + + guard httpResponse.statusCode == 200 else { + weakSelf.complete { completion(result: .Failure(Error.InvalidStatusCode)) } + return + } + + guard let data = data where httpResponse.validateLength(data) else { + weakSelf.complete { completion(result: .Failure(Error.InvalidContentLength)) } + return + } + + guard let image = NSImage.decode(data) else { + weakSelf.complete { completion(result: .Failure(Error.ConversionError)) } + return + } + + if weakSelf.active { + weakSelf.complete { completion(result: Result.Success(image)) } + } + } + + weakSelf.task?.resume() + } + } + + func cancel() { + task?.cancel() + active = false + } + + func complete(closure: () -> Void) { + active = false + + dispatch_async(dispatch_get_main_queue()) { + closure() + } + } +} diff --git a/Sources/Shared/Extensions/NSImage+CGImage.swift b/Sources/Shared/Extensions/NSImage+CGImage.swift new file mode 100644 index 0000000..0f7f240 --- /dev/null +++ b/Sources/Shared/Extensions/NSImage+CGImage.swift @@ -0,0 +1,16 @@ +import Cocoa + +extension NSImage { + + var cgImage: CGImage? { + guard let data = TIFFRepresentation, + source = CGImageSourceCreateWithData(data, nil), + maskRef = CGImageSourceCreateImageAtIndex(source, 0, nil) + else { + return nil + } + + return maskRef + } + +} diff --git a/Sources/Shared/Extensions/NSImage+Cachable.swift b/Sources/Shared/Extensions/NSImage+Cachable.swift new file mode 100644 index 0000000..0dc9f37 --- /dev/null +++ b/Sources/Shared/Extensions/NSImage+Cachable.swift @@ -0,0 +1,11 @@ +import Cocoa +import Cache + +extension NSImage { + + public typealias CacheType = NSImage + + public static func decode(data: NSData) -> CacheType? { + return Decompressor.decompress(data) + } +} diff --git a/Sources/Shared/Extensions/NSImageView.swift b/Sources/Shared/Extensions/NSImageView.swift new file mode 100644 index 0000000..fe8e70d --- /dev/null +++ b/Sources/Shared/Extensions/NSImageView.swift @@ -0,0 +1,66 @@ +import Cocoa + +extension NSImageView { + + public func setImage(URL: NSURL?, placeholder: NSImage? = nil, completion: ((NSImage?) -> ())? = nil) { + image = placeholder + + guard let URL = URL else { return } + + let key = URL.absoluteString + + if let fetcher = fetcher { + fetcher.cancel() + self.fetcher = nil + } + + imageCache.object(key) { [weak self] object in + guard let weakSelf = self else { return } + + if let image = object { + dispatch_async(dispatch_get_main_queue()) { + weakSelf.image = image + completion?(image) + } + + return + } + + if placeholder == nil { + Imaginary.preConfigure?(imageView: weakSelf) + } + + weakSelf.fetcher = Fetcher(URL: URL) + + weakSelf.fetcher?.start { [weak self] result in + guard let weakSelf = self else { return } + + switch result { + case let .Success(image): + Imaginary.transitionClosure(imageView: weakSelf, image: image) + imageCache.add(key, object: image) + completion?(image) + default: + break + } + Imaginary.postConfigure?(imageView: weakSelf) + } + } + } + + var fetcher: Fetcher? { + get { + let wrapper = objc_getAssociatedObject(self, &Capsule.ObjectKey) as? Capsule + let fetcher = wrapper?.value as? Fetcher + return fetcher + } + set (fetcher) { + var wrapper: Capsule? + if let fetcher = fetcher { + wrapper = Capsule(value: fetcher) + } + objc_setAssociatedObject(self, &Capsule.ObjectKey, + wrapper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} From 6be05cc41b14490b33be7bb0d7a4eede23cc9312 Mon Sep 17 00:00:00 2001 From: Christoffer Winterkvist Date: Thu, 23 Jun 2016 14:18:17 +0200 Subject: [PATCH 4/4] Update podspec --- Imaginary.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Imaginary.podspec b/Imaginary.podspec index 0b96798..8398a70 100644 --- a/Imaginary.podspec +++ b/Imaginary.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.osx.source_files = 'Sources/{Mac,Shared}/**/*' s.tvos.source_files = 'Sources/{iOS,Shared}/**/*' - s.frameworks = 'UIKit' + s.frameworks = 'Foundation' s.dependency 'Cache' end