├── .gitignore ├── .swift-version ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Example ├── Gradients │ ├── Gradients.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ ├── Gradients.xcworkspace │ │ └── contents.xcworkspacedata │ ├── Gradients │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── 180 - iPhone 6 Plus.png │ │ │ │ ├── 180 - iPhone 6 Plus@2x-1.png │ │ │ │ ├── 180 - iPhone 6 Plus@2x-2.png │ │ │ │ ├── 180 - iPhone 6 Plus@2x-3.png │ │ │ │ ├── 180 - iPhone 6 Plus@2x-4.png │ │ │ │ ├── 180 - iPhone 6 Plus@2x.png │ │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ │ └── LaunchScreen.storyboard │ │ ├── Cells │ │ │ └── GradientListCell.swift │ │ ├── Color.swift │ │ ├── Font.swift │ │ ├── GradientsController.swift │ │ └── Info.plist │ ├── Podfile │ └── Podfile.lock └── Hex │ ├── Hex.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── Hex.xcworkspace │ └── contents.xcworkspacedata │ ├── Hex │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Cells │ │ └── GridHexCell.swift │ └── Info.plist │ ├── Podfile │ └── Podfile.lock ├── FUNDING.yml ├── Hue.podspec ├── Hue.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── Hue-iOS.xcscheme │ ├── Hue-macOS.xcscheme │ └── Hue-tvOS.xcscheme ├── Images ├── cover.png ├── gradients-screenshot.gif ├── hex-screenshot.png └── icon_v3.png ├── Info ├── Info-iOS.plist ├── Info-macOS.plist └── Info-tvOS.plist ├── LICENSE.md ├── Package.swift ├── README.md ├── Source ├── iOS+tvOS │ ├── UIColor+Hue.swift │ └── UIImage+Hue.swift └── macOS │ ├── NSColor+Hue.swift │ └── NSImage+Hue.swift └── Tests ├── Assets └── Random Access Memories.png ├── iOS+tvOS ├── UIColorTests.swift └── UIImageTests.swift ├── iOS └── Info.plist ├── macOS ├── Info.plist ├── NSColorTests.swift └── NSImageTests.swift └── tvOS └── Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | Icon 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | 10 | # Xcode 11 | # 12 | build/ 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | *.xccheckout 23 | *.moved-aside 24 | DerivedData 25 | *.hmap 26 | *.ipa 27 | *.xcuserstate 28 | 29 | # CocoaPods 30 | Pods 31 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode10.2 2 | language: objective-c 3 | 4 | script: 5 | - set -o pipefail && xcodebuild -project Hue.xcodeproj -scheme "Hue-macOS" -sdk macosx clean build | xcpretty 6 | # - set -o pipefail && xcodebuild -project Hue.xcodeproj -scheme "Hue-macOS" -sdk macosx -enableCodeCoverage YES test | xcpretty 7 | - set -o pipefail && xcodebuild -project Hue.xcodeproj -scheme "Hue-iOS" -sdk iphonesimulator -destination name="iPhone 8" clean build | xcpretty 8 | - set -o pipefail && xcodebuild -project Hue.xcodeproj -scheme "Hue-iOS" -sdk iphonesimulator -destination name="iPhone 8" -enableCodeCoverage YES test | xcpretty 9 | - set -o pipefail && xcodebuild -project Hue.xcodeproj -scheme "Hue-tvOS" -destination 'platform=tvOS Simulator,name=Apple TV,OS=11.4' clean build | xcpretty 10 | - set -o pipefail && xcodebuild -project Hue.xcodeproj -scheme "Hue-tvOS" -destination 'platform=tvOS Simulator,name=Apple TV,OS=11.4' -enableCodeCoverage YES test | xcpretty 11 | 12 | after_success: 13 | - bash <(curl -s https://codecov.io/bash) 14 | 15 | notifications: 16 | email: false 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [Unreleased](https://github.com/hyperoslo/Hue/tree/HEAD) 4 | 5 | [Full Changelog](https://github.com/hyperoslo/Hue/compare/1.1.1...HEAD) 6 | 7 | **Merged pull requests:** 8 | 9 | - Fix/hex init [\#26](https://github.com/hyperoslo/Hue/pull/26) ([zenangst](https://github.com/zenangst)) 10 | 11 | ## [1.1.1](https://github.com/hyperoslo/Hue/tree/1.1.1) (2016-07-07) 12 | [Full Changelog](https://github.com/hyperoslo/Hue/compare/1.1...1.1.1) 13 | 14 | **Merged pull requests:** 15 | 16 | - Fix/broken hex method on mac [\#22](https://github.com/hyperoslo/Hue/pull/22) ([zenangst](https://github.com/zenangst)) 17 | - Color blending and components [\#21](https://github.com/hyperoslo/Hue/pull/21) ([xaanimus](https://github.com/xaanimus)) 18 | - Remove "linking against dylib not safe for use in application extensions" warning [\#19](https://github.com/hyperoslo/Hue/pull/19) ([kumapo](https://github.com/kumapo)) 19 | - Support tvOS [\#18](https://github.com/hyperoslo/Hue/pull/18) ([bcylin](https://github.com/bcylin)) 20 | 21 | ## [1.1](https://github.com/hyperoslo/Hue/tree/1.1) (2016-03-18) 22 | [Full Changelog](https://github.com/hyperoslo/Hue/compare/1.0.1...1.1) 23 | 24 | **Closed issues:** 25 | 26 | - hyper.no doesn't work [\#15](https://github.com/hyperoslo/Hue/issues/15) 27 | - UIImage extensions not exposed in ObjC [\#14](https://github.com/hyperoslo/Hue/issues/14) 28 | 29 | **Merged pull requests:** 30 | 31 | - Add isWhite and isBlack properties [\#17](https://github.com/hyperoslo/Hue/pull/17) ([mttrd](https://github.com/mttrd)) 32 | - Initial Mac version [\#16](https://github.com/hyperoslo/Hue/pull/16) ([rikchilvers](https://github.com/rikchilvers)) 33 | 34 | ## [1.0.1](https://github.com/hyperoslo/Hue/tree/1.0.1) (2016-02-22) 35 | [Full Changelog](https://github.com/hyperoslo/Hue/compare/1.0.0...1.0.1) 36 | 37 | **Merged pull requests:** 38 | 39 | - Return a named tuple [\#13](https://github.com/hyperoslo/Hue/pull/13) ([delba](https://github.com/delba)) 40 | - Minor Code refactoring [\#12](https://github.com/hyperoslo/Hue/pull/12) ([aashishdhawan](https://github.com/aashishdhawan)) 41 | 42 | ## [1.0.0](https://github.com/hyperoslo/Hue/tree/1.0.0) (2016-01-30) 43 | **Closed issues:** 44 | 45 | - Carthage not working properly [\#11](https://github.com/hyperoslo/Hue/issues/11) 46 | 47 | **Merged pull requests:** 48 | 49 | - Add more functions + refactoring [\#10](https://github.com/hyperoslo/Hue/pull/10) ([vadymmarkov](https://github.com/vadymmarkov)) 50 | - Feature/carthage [\#9](https://github.com/hyperoslo/Hue/pull/9) ([vadymmarkov](https://github.com/vadymmarkov)) 51 | - Add Travis [\#8](https://github.com/hyperoslo/Hue/pull/8) ([zenangst](https://github.com/zenangst)) 52 | - Update Hue.podspec [\#7](https://github.com/hyperoslo/Hue/pull/7) ([zenangst](https://github.com/zenangst)) 53 | - Clean up Podfiles in examples [\#6](https://github.com/hyperoslo/Hue/pull/6) ([zenangst](https://github.com/zenangst)) 54 | - Fix tests not passing. [\#5](https://github.com/hyperoslo/Hue/pull/5) ([zenangst](https://github.com/zenangst)) 55 | - Fix crash when getting secondary color [\#4](https://github.com/hyperoslo/Hue/pull/4) ([zenangst](https://github.com/zenangst)) 56 | - Add Gradients example [\#3](https://github.com/hyperoslo/Hue/pull/3) ([zenangst](https://github.com/zenangst)) 57 | - Add cover [\#2](https://github.com/hyperoslo/Hue/pull/2) ([zenangst](https://github.com/zenangst)) 58 | - Update README with Examples [\#1](https://github.com/hyperoslo/Hue/pull/1) ([zenangst](https://github.com/zenangst)) 59 | 60 | 61 | 62 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | GitHub Issues is for reporting bugs, discussing features and general feedback in **Hue**. Be sure to check our [documentation](http://cocoadocs.org/docsets/Hue), [FAQ](https://github.com/hyperoslo/Hue/wiki/FAQ) and [past issues](https://github.com/hyperoslo/Hue/issues?state=closed) before opening any new issues. 2 | 3 | If you are posting about a crash in your application, a stack trace is helpful, but additional context, in the form of code and explanation, is necessary to be of any use. 4 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7B433C03397950BFE84208BB /* Pods_Gradients.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97B355CBF1BF30D4FF55CE37 /* Pods_Gradients.framework */; }; 11 | BDD79C131C33E3E3004828C1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDD79C0C1C33E3E3004828C1 /* AppDelegate.swift */; }; 12 | BDD79C141C33E3E3004828C1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BDD79C0D1C33E3E3004828C1 /* Assets.xcassets */; }; 13 | BDD79C151C33E3E3004828C1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BDD79C0E1C33E3E3004828C1 /* LaunchScreen.storyboard */; }; 14 | BDD79C191C33E41C004828C1 /* GradientsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDD79C181C33E41C004828C1 /* GradientsController.swift */; }; 15 | BDD79C1C1C33EA44004828C1 /* GradientListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDD79C1B1C33EA44004828C1 /* GradientListCell.swift */; }; 16 | BDD79C1F1C33F642004828C1 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDD79C1D1C33F642004828C1 /* Color.swift */; }; 17 | BDD79C201C33F642004828C1 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDD79C1E1C33F642004828C1 /* Font.swift */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 4F3D338A76F1863E784D5433 /* Pods-Gradients.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Gradients.release.xcconfig"; path = "Pods/Target Support Files/Pods-Gradients/Pods-Gradients.release.xcconfig"; sourceTree = ""; }; 22 | 8A65D8AE60F037BAF78F2E5B /* Pods-Gradients.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Gradients.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Gradients/Pods-Gradients.debug.xcconfig"; sourceTree = ""; }; 23 | 97B355CBF1BF30D4FF55CE37 /* Pods_Gradients.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Gradients.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | BDD79C0C1C33E3E3004828C1 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 25 | BDD79C0D1C33E3E3004828C1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 26 | BDD79C0F1C33E3E3004828C1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 27 | BDD79C121C33E3E3004828C1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 28 | BDD79C181C33E41C004828C1 /* GradientsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientsController.swift; sourceTree = ""; }; 29 | BDD79C1B1C33EA44004828C1 /* GradientListCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientListCell.swift; sourceTree = ""; }; 30 | BDD79C1D1C33F642004828C1 /* Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; 31 | BDD79C1E1C33F642004828C1 /* Font.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = ""; }; 32 | BDDDF1701C32B5930087F872 /* Gradients.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gradients.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | CA6288E56E8D691786FA2D88 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | /* End PBXFileReference section */ 35 | 36 | /* Begin PBXFrameworksBuildPhase section */ 37 | BDDDF16D1C32B5930087F872 /* Frameworks */ = { 38 | isa = PBXFrameworksBuildPhase; 39 | buildActionMask = 2147483647; 40 | files = ( 41 | 7B433C03397950BFE84208BB /* Pods_Gradients.framework in Frameworks */, 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | 08BF37192A5CC0CEAAEA34FB /* Pods */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | 8A65D8AE60F037BAF78F2E5B /* Pods-Gradients.debug.xcconfig */, 52 | 4F3D338A76F1863E784D5433 /* Pods-Gradients.release.xcconfig */, 53 | ); 54 | name = Pods; 55 | sourceTree = ""; 56 | }; 57 | 1C267CDA71C06E96EF89E1D1 /* Frameworks */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | CA6288E56E8D691786FA2D88 /* Pods.framework */, 61 | 97B355CBF1BF30D4FF55CE37 /* Pods_Gradients.framework */, 62 | ); 63 | name = Frameworks; 64 | sourceTree = ""; 65 | }; 66 | BDD79C0B1C33E3E3004828C1 /* Gradients */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | BDD79C1D1C33F642004828C1 /* Color.swift */, 70 | BDD79C1E1C33F642004828C1 /* Font.swift */, 71 | BDD79C0C1C33E3E3004828C1 /* AppDelegate.swift */, 72 | BDD79C0D1C33E3E3004828C1 /* Assets.xcassets */, 73 | BDD79C1A1C33EA39004828C1 /* Cells */, 74 | BDD79C181C33E41C004828C1 /* GradientsController.swift */, 75 | BDD79C121C33E3E3004828C1 /* Info.plist */, 76 | BDD79C0E1C33E3E3004828C1 /* LaunchScreen.storyboard */, 77 | ); 78 | path = Gradients; 79 | sourceTree = ""; 80 | }; 81 | BDD79C1A1C33EA39004828C1 /* Cells */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | BDD79C1B1C33EA44004828C1 /* GradientListCell.swift */, 85 | ); 86 | path = Cells; 87 | sourceTree = ""; 88 | }; 89 | BDDDF1671C32B5930087F872 = { 90 | isa = PBXGroup; 91 | children = ( 92 | BDD79C0B1C33E3E3004828C1 /* Gradients */, 93 | BDDDF1711C32B5930087F872 /* Products */, 94 | 1C267CDA71C06E96EF89E1D1 /* Frameworks */, 95 | 08BF37192A5CC0CEAAEA34FB /* Pods */, 96 | ); 97 | sourceTree = ""; 98 | }; 99 | BDDDF1711C32B5930087F872 /* Products */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | BDDDF1701C32B5930087F872 /* Gradients.app */, 103 | ); 104 | name = Products; 105 | sourceTree = ""; 106 | }; 107 | /* End PBXGroup section */ 108 | 109 | /* Begin PBXNativeTarget section */ 110 | BDDDF16F1C32B5930087F872 /* Gradients */ = { 111 | isa = PBXNativeTarget; 112 | buildConfigurationList = BDDDF1821C32B5930087F872 /* Build configuration list for PBXNativeTarget "Gradients" */; 113 | buildPhases = ( 114 | 343835E75C03328B9E32AA75 /* [CP] Check Pods Manifest.lock */, 115 | BDDDF16C1C32B5930087F872 /* Sources */, 116 | BDDDF16D1C32B5930087F872 /* Frameworks */, 117 | BDDDF16E1C32B5930087F872 /* Resources */, 118 | 3BE04C4D5276D149DA46F47B /* [CP] Embed Pods Frameworks */, 119 | EC41F6DF36B1B0BD570689DA /* [CP] Copy Pods Resources */, 120 | ); 121 | buildRules = ( 122 | ); 123 | dependencies = ( 124 | ); 125 | name = Gradients; 126 | productName = Hex; 127 | productReference = BDDDF1701C32B5930087F872 /* Gradients.app */; 128 | productType = "com.apple.product-type.application"; 129 | }; 130 | /* End PBXNativeTarget section */ 131 | 132 | /* Begin PBXProject section */ 133 | BDDDF1681C32B5930087F872 /* Project object */ = { 134 | isa = PBXProject; 135 | attributes = { 136 | LastSwiftUpdateCheck = 0720; 137 | LastUpgradeCheck = 0800; 138 | ORGANIZATIONNAME = Hyper; 139 | TargetAttributes = { 140 | BDDDF16F1C32B5930087F872 = { 141 | CreatedOnToolsVersion = 7.2; 142 | LastSwiftMigration = 0800; 143 | }; 144 | }; 145 | }; 146 | buildConfigurationList = BDDDF16B1C32B5930087F872 /* Build configuration list for PBXProject "Gradients" */; 147 | compatibilityVersion = "Xcode 3.2"; 148 | developmentRegion = English; 149 | hasScannedForEncodings = 0; 150 | knownRegions = ( 151 | en, 152 | Base, 153 | ); 154 | mainGroup = BDDDF1671C32B5930087F872; 155 | productRefGroup = BDDDF1711C32B5930087F872 /* Products */; 156 | projectDirPath = ""; 157 | projectRoot = ""; 158 | targets = ( 159 | BDDDF16F1C32B5930087F872 /* Gradients */, 160 | ); 161 | }; 162 | /* End PBXProject section */ 163 | 164 | /* Begin PBXResourcesBuildPhase section */ 165 | BDDDF16E1C32B5930087F872 /* Resources */ = { 166 | isa = PBXResourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | BDD79C141C33E3E3004828C1 /* Assets.xcassets in Resources */, 170 | BDD79C151C33E3E3004828C1 /* LaunchScreen.storyboard in Resources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXResourcesBuildPhase section */ 175 | 176 | /* Begin PBXShellScriptBuildPhase section */ 177 | 343835E75C03328B9E32AA75 /* [CP] Check Pods Manifest.lock */ = { 178 | isa = PBXShellScriptBuildPhase; 179 | buildActionMask = 2147483647; 180 | files = ( 181 | ); 182 | inputPaths = ( 183 | ); 184 | name = "[CP] Check Pods Manifest.lock"; 185 | outputPaths = ( 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | shellPath = /bin/sh; 189 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 190 | showEnvVarsInLog = 0; 191 | }; 192 | 3BE04C4D5276D149DA46F47B /* [CP] Embed Pods Frameworks */ = { 193 | isa = PBXShellScriptBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | ); 197 | inputPaths = ( 198 | ); 199 | name = "[CP] Embed Pods Frameworks"; 200 | outputPaths = ( 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | shellPath = /bin/sh; 204 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Gradients/Pods-Gradients-frameworks.sh\"\n"; 205 | showEnvVarsInLog = 0; 206 | }; 207 | EC41F6DF36B1B0BD570689DA /* [CP] Copy Pods Resources */ = { 208 | isa = PBXShellScriptBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | ); 212 | inputPaths = ( 213 | ); 214 | name = "[CP] Copy Pods Resources"; 215 | outputPaths = ( 216 | ); 217 | runOnlyForDeploymentPostprocessing = 0; 218 | shellPath = /bin/sh; 219 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Gradients/Pods-Gradients-resources.sh\"\n"; 220 | showEnvVarsInLog = 0; 221 | }; 222 | /* End PBXShellScriptBuildPhase section */ 223 | 224 | /* Begin PBXSourcesBuildPhase section */ 225 | BDDDF16C1C32B5930087F872 /* Sources */ = { 226 | isa = PBXSourcesBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | BDD79C131C33E3E3004828C1 /* AppDelegate.swift in Sources */, 230 | BDD79C1F1C33F642004828C1 /* Color.swift in Sources */, 231 | BDD79C201C33F642004828C1 /* Font.swift in Sources */, 232 | BDD79C1C1C33EA44004828C1 /* GradientListCell.swift in Sources */, 233 | BDD79C191C33E41C004828C1 /* GradientsController.swift in Sources */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | /* End PBXSourcesBuildPhase section */ 238 | 239 | /* Begin PBXVariantGroup section */ 240 | BDD79C0E1C33E3E3004828C1 /* LaunchScreen.storyboard */ = { 241 | isa = PBXVariantGroup; 242 | children = ( 243 | BDD79C0F1C33E3E3004828C1 /* Base */, 244 | ); 245 | name = LaunchScreen.storyboard; 246 | sourceTree = ""; 247 | }; 248 | /* End PBXVariantGroup section */ 249 | 250 | /* Begin XCBuildConfiguration section */ 251 | BDDDF1801C32B5930087F872 /* Debug */ = { 252 | isa = XCBuildConfiguration; 253 | buildSettings = { 254 | ALWAYS_SEARCH_USER_PATHS = NO; 255 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 256 | CLANG_CXX_LIBRARY = "libc++"; 257 | CLANG_ENABLE_MODULES = YES; 258 | CLANG_ENABLE_OBJC_ARC = YES; 259 | CLANG_WARN_BOOL_CONVERSION = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_EMPTY_BODY = YES; 263 | CLANG_WARN_ENUM_CONVERSION = YES; 264 | CLANG_WARN_INFINITE_RECURSION = YES; 265 | CLANG_WARN_INT_CONVERSION = YES; 266 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 267 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 268 | CLANG_WARN_UNREACHABLE_CODE = YES; 269 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 270 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 271 | COPY_PHASE_STRIP = NO; 272 | DEBUG_INFORMATION_FORMAT = dwarf; 273 | ENABLE_STRICT_OBJC_MSGSEND = YES; 274 | ENABLE_TESTABILITY = YES; 275 | GCC_C_LANGUAGE_STANDARD = gnu99; 276 | GCC_DYNAMIC_NO_PIC = NO; 277 | GCC_NO_COMMON_BLOCKS = YES; 278 | GCC_OPTIMIZATION_LEVEL = 0; 279 | GCC_PREPROCESSOR_DEFINITIONS = ( 280 | "DEBUG=1", 281 | "$(inherited)", 282 | ); 283 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 284 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 285 | GCC_WARN_UNDECLARED_SELECTOR = YES; 286 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 287 | GCC_WARN_UNUSED_FUNCTION = YES; 288 | GCC_WARN_UNUSED_VARIABLE = YES; 289 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 290 | MTL_ENABLE_DEBUG_INFO = YES; 291 | ONLY_ACTIVE_ARCH = YES; 292 | SDKROOT = iphoneos; 293 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 294 | SWIFT_VERSION = 3.0; 295 | }; 296 | name = Debug; 297 | }; 298 | BDDDF1811C32B5930087F872 /* Release */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ALWAYS_SEARCH_USER_PATHS = NO; 302 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 303 | CLANG_CXX_LIBRARY = "libc++"; 304 | CLANG_ENABLE_MODULES = YES; 305 | CLANG_ENABLE_OBJC_ARC = YES; 306 | CLANG_WARN_BOOL_CONVERSION = YES; 307 | CLANG_WARN_CONSTANT_CONVERSION = YES; 308 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 309 | CLANG_WARN_EMPTY_BODY = YES; 310 | CLANG_WARN_ENUM_CONVERSION = YES; 311 | CLANG_WARN_INFINITE_RECURSION = YES; 312 | CLANG_WARN_INT_CONVERSION = YES; 313 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 314 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 315 | CLANG_WARN_UNREACHABLE_CODE = YES; 316 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 317 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 318 | COPY_PHASE_STRIP = NO; 319 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 320 | ENABLE_NS_ASSERTIONS = NO; 321 | ENABLE_STRICT_OBJC_MSGSEND = YES; 322 | GCC_C_LANGUAGE_STANDARD = gnu99; 323 | GCC_NO_COMMON_BLOCKS = YES; 324 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 325 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 326 | GCC_WARN_UNDECLARED_SELECTOR = YES; 327 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 328 | GCC_WARN_UNUSED_FUNCTION = YES; 329 | GCC_WARN_UNUSED_VARIABLE = YES; 330 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 331 | MTL_ENABLE_DEBUG_INFO = NO; 332 | SDKROOT = iphoneos; 333 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 334 | SWIFT_VERSION = 3.0; 335 | VALIDATE_PRODUCT = YES; 336 | }; 337 | name = Release; 338 | }; 339 | BDDDF1831C32B5930087F872 /* Debug */ = { 340 | isa = XCBuildConfiguration; 341 | baseConfigurationReference = 8A65D8AE60F037BAF78F2E5B /* Pods-Gradients.debug.xcconfig */; 342 | buildSettings = { 343 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 344 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 345 | INFOPLIST_FILE = "$(SRCROOT)/Gradients/Info.plist"; 346 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 347 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Hex; 348 | PRODUCT_NAME = Gradients; 349 | SWIFT_VERSION = 3.0; 350 | }; 351 | name = Debug; 352 | }; 353 | BDDDF1841C32B5930087F872 /* Release */ = { 354 | isa = XCBuildConfiguration; 355 | baseConfigurationReference = 4F3D338A76F1863E784D5433 /* Pods-Gradients.release.xcconfig */; 356 | buildSettings = { 357 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 358 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 359 | INFOPLIST_FILE = "$(SRCROOT)/Gradients/Info.plist"; 360 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 361 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Hex; 362 | PRODUCT_NAME = Gradients; 363 | SWIFT_VERSION = 3.0; 364 | }; 365 | name = Release; 366 | }; 367 | /* End XCBuildConfiguration section */ 368 | 369 | /* Begin XCConfigurationList section */ 370 | BDDDF16B1C32B5930087F872 /* Build configuration list for PBXProject "Gradients" */ = { 371 | isa = XCConfigurationList; 372 | buildConfigurations = ( 373 | BDDDF1801C32B5930087F872 /* Debug */, 374 | BDDDF1811C32B5930087F872 /* Release */, 375 | ); 376 | defaultConfigurationIsVisible = 0; 377 | defaultConfigurationName = Release; 378 | }; 379 | BDDDF1821C32B5930087F872 /* Build configuration list for PBXNativeTarget "Gradients" */ = { 380 | isa = XCConfigurationList; 381 | buildConfigurations = ( 382 | BDDDF1831C32B5930087F872 /* Debug */, 383 | BDDDF1841C32B5930087F872 /* Release */, 384 | ); 385 | defaultConfigurationIsVisible = 0; 386 | defaultConfigurationName = Release; 387 | }; 388 | /* End XCConfigurationList section */ 389 | }; 390 | rootObject = BDDDF1681C32B5930087F872 /* Project object */; 391 | } 392 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Spots 3 | 4 | @UIApplicationMain 5 | class AppDelegate: UIResponder, UIApplicationDelegate { 6 | 7 | var window: UIWindow? 8 | var navigationController: UINavigationController? 9 | 10 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 11 | window = UIWindow(frame: UIScreen.main.bounds) 12 | 13 | Component.configure = { component in 14 | let tableView = component.tableView 15 | 16 | tableView?.backgroundColor = UIColor.clear 17 | tableView?.tableFooterView = UIView(frame: CGRect.zero) 18 | tableView?.separatorInset = UIEdgeInsets(top: 10, 19 | left: 10, 20 | bottom: 10, 21 | right: 10) 22 | tableView?.separatorColor = Color.cellSeparator 23 | } 24 | 25 | Configuration.registerDefault(view: GradientListCell.self) 26 | 27 | let controller = GradientsController(title: "Gradients") 28 | let navigationController = UINavigationController(rootViewController: controller) 29 | 30 | window?.rootViewController = navigationController 31 | window?.makeKeyAndVisible() 32 | 33 | applyStyles() 34 | 35 | return true 36 | } 37 | 38 | fileprivate func applyStyles() { 39 | let navigationBar = UINavigationBar.appearance() 40 | navigationBar.barStyle = .black 41 | navigationBar.isTranslucent = false 42 | navigationBar.titleTextAttributes = [ 43 | NSForegroundColorAttributeName: Color.navigationBarForeground, 44 | NSFontAttributeName: Font.navigationBar 45 | ] 46 | navigationBar.tintColor = Color.navigationBarForeground 47 | navigationBar.barTintColor = UIColor(red:0.333, green:0.220, blue:0.478, alpha: 1) 48 | navigationBar.shadowImage = UIImage() 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus.png -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x-1.png -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x-2.png -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x-3.png -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x-4.png -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/180 - iPhone 6 Plus@2x.png -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "180 - iPhone 6 Plus@2x-2.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "180 - iPhone 6 Plus@2x-1.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "180 - iPhone 6 Plus@2x-3.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "180 - iPhone 6 Plus@2x-4.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "180 - iPhone 6 Plus.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "180 - iPhone 6 Plus@2x.png", 37 | "scale" : "3x" 38 | } 39 | ], 40 | "info" : { 41 | "version" : 1, 42 | "author" : "xcode" 43 | }, 44 | "properties" : { 45 | "pre-rendered" : true 46 | } 47 | } -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Cells/GradientListCell.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Spots 3 | import Hue 4 | 5 | class GradientListCell: UITableViewCell, ItemConfigurable { 6 | 7 | lazy var selectedView: UIView = { 8 | let view = UIView() 9 | view.backgroundColor = Color.cellSelectedColor 10 | 11 | return view 12 | }() 13 | 14 | func configure(with item: Item) { 15 | textLabel?.textColor = UIColor(hex:"#fff").alpha(0.8) 16 | textLabel?.text = item.title 17 | textLabel?.font = Font.cell 18 | selectedBackgroundView = selectedView 19 | backgroundColor = UIColor.clear 20 | } 21 | 22 | func computeSize(for item: Item) -> CGSize { 23 | return CGSize(width: 64, height: 64) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Color.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | struct Color { 4 | 5 | static let navigationBarForeground = UIColor(red: 255, green: 255, blue: 255, alpha: 0.9) 6 | static let cellForeground = UIColor(red: 255, green: 255, blue: 255, alpha: 0.8) 7 | static let cellSeparator = UIColor(red: 255, green: 255, blue: 255, alpha: 0.2) 8 | static let cellSelectedColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.1) 9 | } 10 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Font.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | struct Font { 4 | 5 | static let navigationBar = UIFont(name: "Avenir-Heavy", size: 20)! 6 | static let cell = UIFont(name: "Avenir-Medium", size: 18)! 7 | 8 | } 9 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients/GradientsController.swift: -------------------------------------------------------------------------------- 1 | import Spots 2 | import Hue 3 | import Fakery 4 | import Sugar 5 | 6 | class GradientsController: SpotsController { 7 | 8 | static let faker = Faker() 9 | 10 | lazy var gradient: CAGradientLayer = [ 11 | UIColor(hex:"#FD4340"), 12 | UIColor(hex:"#CE2BAE") 13 | ].gradient { gradient in 14 | gradient.speed = 0 15 | gradient.timeOffset = 0 16 | 17 | return gradient 18 | } 19 | 20 | lazy var animation: CABasicAnimation = { [unowned self] in 21 | let animation = CABasicAnimation(keyPath: "colors") 22 | animation.duration = 1.0 23 | animation.isRemovedOnCompletion = false 24 | 25 | return animation 26 | }() 27 | 28 | convenience init(title: String) { 29 | let model = ComponentModel(kind: .list) 30 | let component = Component(model: model) 31 | self.init(component: component) 32 | self.title = title 33 | 34 | animation.fromValue = gradient.colors 35 | animation.toValue = [ 36 | UIColor(hex:"#8D24FF").cgColor, 37 | UIColor(hex:"#23A8F9").cgColor 38 | ] 39 | } 40 | 41 | override func viewDidLoad() { 42 | super.viewDidLoad() 43 | 44 | scrollView.backgroundColor = UIColor.clear 45 | scrollView.contentInset.bottom = 64 46 | 47 | dispatch(queue: .interactive) { [weak self] in 48 | self?.update { 49 | $0.model.items = GradientsController.generateItems(0, to: 50) 50 | } 51 | } 52 | } 53 | 54 | override func viewDidAppear(_ animated: Bool) { 55 | super.viewDidAppear(animated) 56 | 57 | guard let navigationController = navigationController else { return } 58 | 59 | navigationController.view.layer.insertSublayer(gradient, at: 0) 60 | gradient.timeOffset = 0 61 | gradient.bounds = navigationController.view.bounds 62 | gradient.frame = navigationController.view.bounds 63 | gradient.add(animation, forKey: "Change Colors") 64 | } 65 | 66 | override func scrollViewDidScroll(_ scrollView: UIScrollView) { 67 | updateGradient() 68 | } 69 | 70 | fileprivate func updateGradient() { 71 | let offset = scrollView.contentOffset.y / scrollView.contentSize.height 72 | 73 | if offset >= 0 && offset <= CGFloat(animation.duration) { 74 | gradient.timeOffset = CFTimeInterval(offset) 75 | } else if offset >= CGFloat(animation.duration) { 76 | gradient.timeOffset = CFTimeInterval(animation.duration) 77 | } 78 | 79 | updateNavigationBarColor() 80 | } 81 | 82 | fileprivate func updateNavigationBarColor() { 83 | guard let navigationBar = navigationController?.navigationBar else { return } 84 | 85 | if let gradientLayer = gradient.presentation(), 86 | let colors = gradientLayer.value(forKey: "colors") as? [CGColor], 87 | let firstColor = colors.first { 88 | navigationBar.barTintColor = UIColor(cgColor: firstColor) 89 | } else if let color = gradient.colors as? [CGColor], 90 | let firstColor = color.first { 91 | navigationBar.barTintColor = UIColor(cgColor: firstColor) 92 | } 93 | } 94 | 95 | static func generateItem(_ index: Int) -> Item { 96 | return Item(title: faker.lorem.sentence()) 97 | } 98 | 99 | static func generateItems(_ from: Int, to: Int) -> [Item] { 100 | var items = [Item]() 101 | for i in from...from+to { 102 | autoreleasepool(invoking: { items.append(generateItem(i)) }) 103 | } 104 | return items 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Example/Gradients/Gradients/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarHidden 32 | 33 | UIStatusBarStyle 34 | UIStatusBarStyleLightContent 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | UIViewControllerBasedStatusBarAppearance 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Example/Gradients/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform :ios, '9.0' 4 | 5 | use_frameworks! 6 | inhibit_all_warnings! 7 | 8 | target 'Gradients' 9 | 10 | pod 'Hue', path: '../../' 11 | pod 'Imaginary', git: 'https://github.com/hyperoslo/Imaginary' 12 | pod 'Cache', git: 'https://github.com/hyperoslo/Cache' 13 | pod 'Spots', git: 'https://github.com/hyperoslo/Spots' 14 | pod 'Sugar', git: 'https://github.com/hyperoslo/Sugar' 15 | pod 'Tailor' 16 | pod 'Fakery' 17 | -------------------------------------------------------------------------------- /Example/Gradients/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Cache (3.3.0): 3 | - SwiftHash (~> 1.4.0) 4 | - Fakery (2.0.0) 5 | - Hue (2.0.1) 6 | - Imaginary (2.0.0): 7 | - Cache (~> 3.0) 8 | - Spots (6.0.3): 9 | - Spots/Core (= 6.0.3) 10 | - Spots/Core (6.0.3): 11 | - Cache (~> 3.0) 12 | - Tailor (~> 2.0) 13 | - Sugar (3.1.2) 14 | - SwiftHash (1.4.0) 15 | - Tailor (2.2.1) 16 | 17 | DEPENDENCIES: 18 | - Cache (from `https://github.com/hyperoslo/Cache`) 19 | - Fakery 20 | - Hue (from `../../`) 21 | - Imaginary (from `https://github.com/hyperoslo/Imaginary`) 22 | - Spots (from `https://github.com/hyperoslo/Spots`) 23 | - Sugar (from `https://github.com/hyperoslo/Sugar`) 24 | - Tailor 25 | 26 | EXTERNAL SOURCES: 27 | Cache: 28 | :git: https://github.com/hyperoslo/Cache 29 | Hue: 30 | :path: "../../" 31 | Imaginary: 32 | :git: https://github.com/hyperoslo/Imaginary 33 | Spots: 34 | :git: https://github.com/hyperoslo/Spots 35 | Sugar: 36 | :git: https://github.com/hyperoslo/Sugar 37 | 38 | CHECKOUT OPTIONS: 39 | Cache: 40 | :commit: 4699caf4a994996840826a504270fb1ea6ac0a4f 41 | :git: https://github.com/hyperoslo/Cache 42 | Imaginary: 43 | :commit: 3176aad7a2834a966074f859fd133497532dd4d9 44 | :git: https://github.com/hyperoslo/Imaginary 45 | Spots: 46 | :commit: b99fce2737a2380fb516f1355c70ac5d4e85b356 47 | :git: https://github.com/hyperoslo/Spots 48 | Sugar: 49 | :commit: 60dfbe15325ef31cce29db4b59db7e7590c095fa 50 | :git: https://github.com/hyperoslo/Sugar 51 | 52 | SPEC CHECKSUMS: 53 | Cache: adbacf2672fbc9d48f552e03bbd4916510c39ac0 54 | Fakery: 97b99c23937d2e025d9135c75e2b17351ccd5031 55 | Hue: ab7efb15270e0bc764f2f468aa6f3f2728d52f2b 56 | Imaginary: 642c6eb34ff2bd52404a70044599a8e2693e1e44 57 | Spots: ed7d2d6a47de7a7a0a0ed83a9b9f4484f76dc418 58 | Sugar: 41f2efa0244806f524ff2d77c951a6a43e81a0f3 59 | SwiftHash: acf0f29032309a5c7a7f625595eade1aca97aca2 60 | Tailor: caabfebed676fab6e00c0c173e05294ccf89861e 61 | 62 | PODFILE CHECKSUM: da722dab3521a4e945220198b5ef439a564db215 63 | 64 | COCOAPODS: 1.2.1 65 | -------------------------------------------------------------------------------- /Example/Hex/Hex.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 160F59CE2445166F0BD3155D /* Pods_Hex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1E00E32F57180633A2D333 /* Pods_Hex.framework */; }; 11 | BDDDF1741C32B5930087F872 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDDDF1731C32B5930087F872 /* AppDelegate.swift */; }; 12 | BDDDF17B1C32B5930087F872 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BDDDF17A1C32B5930087F872 /* Assets.xcassets */; }; 13 | BDDDF17E1C32B5930087F872 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BDDDF17C1C32B5930087F872 /* LaunchScreen.storyboard */; }; 14 | BDDDF1871C32B8C10087F872 /* GridHexCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDDDF1861C32B8C10087F872 /* GridHexCell.swift */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 6F44696A072438CD35F6EEE4 /* Pods-Hex.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Hex.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Hex/Pods-Hex.debug.xcconfig"; sourceTree = ""; }; 19 | BDDDF1701C32B5930087F872 /* Hex.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Hex.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | BDDDF1731C32B5930087F872 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 21 | BDDDF17A1C32B5930087F872 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 22 | BDDDF17D1C32B5930087F872 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 23 | BDDDF17F1C32B5930087F872 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 24 | BDDDF1861C32B8C10087F872 /* GridHexCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridHexCell.swift; sourceTree = ""; }; 25 | CA6288E56E8D691786FA2D88 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | CE1E00E32F57180633A2D333 /* Pods_Hex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Hex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | EA05BE2765B470AF8C4274B8 /* Pods-Hex.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Hex.release.xcconfig"; path = "Pods/Target Support Files/Pods-Hex/Pods-Hex.release.xcconfig"; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | BDDDF16D1C32B5930087F872 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | 160F59CE2445166F0BD3155D /* Pods_Hex.framework in Frameworks */, 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 1C267CDA71C06E96EF89E1D1 /* Frameworks */ = { 43 | isa = PBXGroup; 44 | children = ( 45 | CA6288E56E8D691786FA2D88 /* Pods.framework */, 46 | CE1E00E32F57180633A2D333 /* Pods_Hex.framework */, 47 | ); 48 | name = Frameworks; 49 | sourceTree = ""; 50 | }; 51 | 5178A464AA76A5B1011B6947 /* Pods */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | 6F44696A072438CD35F6EEE4 /* Pods-Hex.debug.xcconfig */, 55 | EA05BE2765B470AF8C4274B8 /* Pods-Hex.release.xcconfig */, 56 | ); 57 | name = Pods; 58 | sourceTree = ""; 59 | }; 60 | BDDDF1671C32B5930087F872 = { 61 | isa = PBXGroup; 62 | children = ( 63 | BDDDF1721C32B5930087F872 /* Hex */, 64 | BDDDF1711C32B5930087F872 /* Products */, 65 | 1C267CDA71C06E96EF89E1D1 /* Frameworks */, 66 | 5178A464AA76A5B1011B6947 /* Pods */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | BDDDF1711C32B5930087F872 /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | BDDDF1701C32B5930087F872 /* Hex.app */, 74 | ); 75 | name = Products; 76 | sourceTree = ""; 77 | }; 78 | BDDDF1721C32B5930087F872 /* Hex */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | BDDDF1851C32B8C10087F872 /* Cells */, 82 | BDDDF1731C32B5930087F872 /* AppDelegate.swift */, 83 | BDDDF17A1C32B5930087F872 /* Assets.xcassets */, 84 | BDDDF17C1C32B5930087F872 /* LaunchScreen.storyboard */, 85 | BDDDF17F1C32B5930087F872 /* Info.plist */, 86 | ); 87 | path = Hex; 88 | sourceTree = ""; 89 | }; 90 | BDDDF1851C32B8C10087F872 /* Cells */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | BDDDF1861C32B8C10087F872 /* GridHexCell.swift */, 94 | ); 95 | path = Cells; 96 | sourceTree = ""; 97 | }; 98 | /* End PBXGroup section */ 99 | 100 | /* Begin PBXNativeTarget section */ 101 | BDDDF16F1C32B5930087F872 /* Hex */ = { 102 | isa = PBXNativeTarget; 103 | buildConfigurationList = BDDDF1821C32B5930087F872 /* Build configuration list for PBXNativeTarget "Hex" */; 104 | buildPhases = ( 105 | C5E74AB3C56A11ED54ED82AF /* [CP] Check Pods Manifest.lock */, 106 | BDDDF16C1C32B5930087F872 /* Sources */, 107 | BDDDF16D1C32B5930087F872 /* Frameworks */, 108 | BDDDF16E1C32B5930087F872 /* Resources */, 109 | 0E9A8444F9D7DD023227DA86 /* [CP] Embed Pods Frameworks */, 110 | FB53618D734FF8F899D4DBDB /* [CP] Copy Pods Resources */, 111 | ); 112 | buildRules = ( 113 | ); 114 | dependencies = ( 115 | ); 116 | name = Hex; 117 | productName = Hex; 118 | productReference = BDDDF1701C32B5930087F872 /* Hex.app */; 119 | productType = "com.apple.product-type.application"; 120 | }; 121 | /* End PBXNativeTarget section */ 122 | 123 | /* Begin PBXProject section */ 124 | BDDDF1681C32B5930087F872 /* Project object */ = { 125 | isa = PBXProject; 126 | attributes = { 127 | LastSwiftUpdateCheck = 0720; 128 | LastUpgradeCheck = 0800; 129 | ORGANIZATIONNAME = Hyper; 130 | TargetAttributes = { 131 | BDDDF16F1C32B5930087F872 = { 132 | CreatedOnToolsVersion = 7.2; 133 | LastSwiftMigration = 0800; 134 | }; 135 | }; 136 | }; 137 | buildConfigurationList = BDDDF16B1C32B5930087F872 /* Build configuration list for PBXProject "Hex" */; 138 | compatibilityVersion = "Xcode 3.2"; 139 | developmentRegion = English; 140 | hasScannedForEncodings = 0; 141 | knownRegions = ( 142 | en, 143 | Base, 144 | ); 145 | mainGroup = BDDDF1671C32B5930087F872; 146 | productRefGroup = BDDDF1711C32B5930087F872 /* Products */; 147 | projectDirPath = ""; 148 | projectRoot = ""; 149 | targets = ( 150 | BDDDF16F1C32B5930087F872 /* Hex */, 151 | ); 152 | }; 153 | /* End PBXProject section */ 154 | 155 | /* Begin PBXResourcesBuildPhase section */ 156 | BDDDF16E1C32B5930087F872 /* Resources */ = { 157 | isa = PBXResourcesBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | BDDDF17E1C32B5930087F872 /* LaunchScreen.storyboard in Resources */, 161 | BDDDF17B1C32B5930087F872 /* Assets.xcassets in Resources */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | /* End PBXResourcesBuildPhase section */ 166 | 167 | /* Begin PBXShellScriptBuildPhase section */ 168 | 0E9A8444F9D7DD023227DA86 /* [CP] Embed Pods Frameworks */ = { 169 | isa = PBXShellScriptBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | ); 173 | inputPaths = ( 174 | ); 175 | name = "[CP] Embed Pods Frameworks"; 176 | outputPaths = ( 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | shellPath = /bin/sh; 180 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Hex/Pods-Hex-frameworks.sh\"\n"; 181 | showEnvVarsInLog = 0; 182 | }; 183 | C5E74AB3C56A11ED54ED82AF /* [CP] Check Pods Manifest.lock */ = { 184 | isa = PBXShellScriptBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | ); 188 | inputPaths = ( 189 | ); 190 | name = "[CP] Check Pods Manifest.lock"; 191 | outputPaths = ( 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | shellPath = /bin/sh; 195 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 196 | showEnvVarsInLog = 0; 197 | }; 198 | FB53618D734FF8F899D4DBDB /* [CP] Copy Pods Resources */ = { 199 | isa = PBXShellScriptBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | ); 203 | inputPaths = ( 204 | ); 205 | name = "[CP] Copy Pods Resources"; 206 | outputPaths = ( 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | shellPath = /bin/sh; 210 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Hex/Pods-Hex-resources.sh\"\n"; 211 | showEnvVarsInLog = 0; 212 | }; 213 | /* End PBXShellScriptBuildPhase section */ 214 | 215 | /* Begin PBXSourcesBuildPhase section */ 216 | BDDDF16C1C32B5930087F872 /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | BDDDF1741C32B5930087F872 /* AppDelegate.swift in Sources */, 221 | BDDDF1871C32B8C10087F872 /* GridHexCell.swift in Sources */, 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | }; 225 | /* End PBXSourcesBuildPhase section */ 226 | 227 | /* Begin PBXVariantGroup section */ 228 | BDDDF17C1C32B5930087F872 /* LaunchScreen.storyboard */ = { 229 | isa = PBXVariantGroup; 230 | children = ( 231 | BDDDF17D1C32B5930087F872 /* Base */, 232 | ); 233 | name = LaunchScreen.storyboard; 234 | sourceTree = ""; 235 | }; 236 | /* End PBXVariantGroup section */ 237 | 238 | /* Begin XCBuildConfiguration section */ 239 | BDDDF1801C32B5930087F872 /* Debug */ = { 240 | isa = XCBuildConfiguration; 241 | buildSettings = { 242 | ALWAYS_SEARCH_USER_PATHS = NO; 243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 244 | CLANG_CXX_LIBRARY = "libc++"; 245 | CLANG_ENABLE_MODULES = YES; 246 | CLANG_ENABLE_OBJC_ARC = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 250 | CLANG_WARN_EMPTY_BODY = YES; 251 | CLANG_WARN_ENUM_CONVERSION = YES; 252 | CLANG_WARN_INFINITE_RECURSION = YES; 253 | CLANG_WARN_INT_CONVERSION = YES; 254 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 255 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 256 | CLANG_WARN_UNREACHABLE_CODE = YES; 257 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 258 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 259 | COPY_PHASE_STRIP = NO; 260 | DEBUG_INFORMATION_FORMAT = dwarf; 261 | ENABLE_STRICT_OBJC_MSGSEND = YES; 262 | ENABLE_TESTABILITY = YES; 263 | GCC_C_LANGUAGE_STANDARD = gnu99; 264 | GCC_DYNAMIC_NO_PIC = NO; 265 | GCC_NO_COMMON_BLOCKS = YES; 266 | GCC_OPTIMIZATION_LEVEL = 0; 267 | GCC_PREPROCESSOR_DEFINITIONS = ( 268 | "DEBUG=1", 269 | "$(inherited)", 270 | ); 271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 273 | GCC_WARN_UNDECLARED_SELECTOR = YES; 274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 275 | GCC_WARN_UNUSED_FUNCTION = YES; 276 | GCC_WARN_UNUSED_VARIABLE = YES; 277 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 278 | MTL_ENABLE_DEBUG_INFO = YES; 279 | ONLY_ACTIVE_ARCH = YES; 280 | SDKROOT = iphoneos; 281 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 282 | SWIFT_VERSION = 3.0; 283 | }; 284 | name = Debug; 285 | }; 286 | BDDDF1811C32B5930087F872 /* Release */ = { 287 | isa = XCBuildConfiguration; 288 | buildSettings = { 289 | ALWAYS_SEARCH_USER_PATHS = NO; 290 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 291 | CLANG_CXX_LIBRARY = "libc++"; 292 | CLANG_ENABLE_MODULES = YES; 293 | CLANG_ENABLE_OBJC_ARC = YES; 294 | CLANG_WARN_BOOL_CONVERSION = YES; 295 | CLANG_WARN_CONSTANT_CONVERSION = YES; 296 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 297 | CLANG_WARN_EMPTY_BODY = YES; 298 | CLANG_WARN_ENUM_CONVERSION = YES; 299 | CLANG_WARN_INFINITE_RECURSION = YES; 300 | CLANG_WARN_INT_CONVERSION = YES; 301 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 302 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 303 | CLANG_WARN_UNREACHABLE_CODE = YES; 304 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 305 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 306 | COPY_PHASE_STRIP = NO; 307 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 308 | ENABLE_NS_ASSERTIONS = NO; 309 | ENABLE_STRICT_OBJC_MSGSEND = YES; 310 | GCC_C_LANGUAGE_STANDARD = gnu99; 311 | GCC_NO_COMMON_BLOCKS = YES; 312 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 313 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 314 | GCC_WARN_UNDECLARED_SELECTOR = YES; 315 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 316 | GCC_WARN_UNUSED_FUNCTION = YES; 317 | GCC_WARN_UNUSED_VARIABLE = YES; 318 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 319 | MTL_ENABLE_DEBUG_INFO = NO; 320 | SDKROOT = iphoneos; 321 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 322 | SWIFT_VERSION = 3.0; 323 | VALIDATE_PRODUCT = YES; 324 | }; 325 | name = Release; 326 | }; 327 | BDDDF1831C32B5930087F872 /* Debug */ = { 328 | isa = XCBuildConfiguration; 329 | baseConfigurationReference = 6F44696A072438CD35F6EEE4 /* Pods-Hex.debug.xcconfig */; 330 | buildSettings = { 331 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 332 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 333 | INFOPLIST_FILE = Hex/Info.plist; 334 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 335 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Hex; 336 | PRODUCT_NAME = "$(TARGET_NAME)"; 337 | SWIFT_VERSION = 3.0; 338 | }; 339 | name = Debug; 340 | }; 341 | BDDDF1841C32B5930087F872 /* Release */ = { 342 | isa = XCBuildConfiguration; 343 | baseConfigurationReference = EA05BE2765B470AF8C4274B8 /* Pods-Hex.release.xcconfig */; 344 | buildSettings = { 345 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 346 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 347 | INFOPLIST_FILE = Hex/Info.plist; 348 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 349 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Hex; 350 | PRODUCT_NAME = "$(TARGET_NAME)"; 351 | SWIFT_VERSION = 3.0; 352 | }; 353 | name = Release; 354 | }; 355 | /* End XCBuildConfiguration section */ 356 | 357 | /* Begin XCConfigurationList section */ 358 | BDDDF16B1C32B5930087F872 /* Build configuration list for PBXProject "Hex" */ = { 359 | isa = XCConfigurationList; 360 | buildConfigurations = ( 361 | BDDDF1801C32B5930087F872 /* Debug */, 362 | BDDDF1811C32B5930087F872 /* Release */, 363 | ); 364 | defaultConfigurationIsVisible = 0; 365 | defaultConfigurationName = Release; 366 | }; 367 | BDDDF1821C32B5930087F872 /* Build configuration list for PBXNativeTarget "Hex" */ = { 368 | isa = XCConfigurationList; 369 | buildConfigurations = ( 370 | BDDDF1831C32B5930087F872 /* Debug */, 371 | BDDDF1841C32B5930087F872 /* Release */, 372 | ); 373 | defaultConfigurationIsVisible = 0; 374 | defaultConfigurationName = Release; 375 | }; 376 | /* End XCConfigurationList section */ 377 | }; 378 | rootObject = BDDDF1681C32B5930087F872 /* Project object */; 379 | } 380 | -------------------------------------------------------------------------------- /Example/Hex/Hex.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Hex/Hex.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Hex/Hex/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Spots 3 | 4 | @UIApplicationMain 5 | class AppDelegate: UIResponder, UIApplicationDelegate { 6 | 7 | var window: UIWindow? 8 | var navigationController: UINavigationController? 9 | 10 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 11 | 12 | window = UIWindow(frame: UIScreen.main.bounds) 13 | 14 | Configuration.registerDefault(view: GridHexCell.self) 15 | Component.configure = { 16 | $0.collectionView?.backgroundColor = UIColor.black 17 | } 18 | 19 | let layout = Layout(span: 3, 20 | inset: Inset(top: 5, left: 15, bottom: 15, right: 15)) 21 | 22 | let componentModels: [ComponentModel] = [ 23 | ComponentModel(kind: .carousel, layout: layout, items: [ 24 | Item(title: "#00FFFF"), 25 | Item(title: "#FF00FF"), 26 | Item(title: "#FFFF00"), 27 | Item(title: "#000000") 28 | ]), 29 | ComponentModel(kind: .carousel, layout: layout, items: [ 30 | Item(title: "#3b5998"), 31 | Item(title: "#8b9dc3"), 32 | Item(title: "#dfe3ee"), 33 | Item(title: "#f7f7f7"), 34 | Item(title: "#ffffff") 35 | ]), 36 | ComponentModel(kind: .carousel, layout: layout, items: [ 37 | Item(title: "#ee4035"), 38 | Item(title: "#f37736"), 39 | Item(title: "#fdf498"), 40 | Item(title: "#7bc043"), 41 | Item(title: "#0392cf") 42 | ]), 43 | ComponentModel(kind: .carousel, layout: layout, items: [ 44 | Item(title: "#96ceb4"), 45 | Item(title: "#ffeead"), 46 | Item(title: "#ff6f69"), 47 | Item(title: "#ffcc5c"), 48 | Item(title: "#88d8b0") 49 | ]), 50 | ] 51 | 52 | let components = componentModels.map { Component(model: $0) } 53 | let controller = SpotsController(components: components) 54 | 55 | controller.scrollView.contentInset.top = 15 56 | 57 | window?.rootViewController = controller 58 | window?.makeKeyAndVisible() 59 | 60 | return true 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /Example/Hex/Hex/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Example/Hex/Hex/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/Hex/Hex/Cells/GridHexCell.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Sugar 3 | import Spots 4 | import Hue 5 | 6 | class GridHexCell: UICollectionViewCell, ItemConfigurable { 7 | 8 | lazy var label: UILabel = { [unowned self] in 9 | let label = UILabel(frame: CGRect.zero) 10 | label.font = UIFont.boldSystemFont(ofSize: 11) 11 | label.numberOfLines = 4 12 | label.textAlignment = .center 13 | 14 | return label 15 | }() 16 | 17 | override init(frame: CGRect) { 18 | super.init(frame: frame) 19 | contentView.addSubview(label) 20 | } 21 | 22 | required init?(coder aDecoder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | func configure(with item: Item) { 27 | let color = UIColor(hex:item.title) 28 | backgroundColor = color 29 | 30 | label.textColor = color.isDark ? UIColor.white : UIColor.darkGray 31 | label.attributedText = NSAttributedString(string: item.title, 32 | attributes: nil) 33 | label.frame.size.height = 44 34 | label.frame.size.width = contentView.frame.size.width - 7.5 35 | } 36 | 37 | func computeSize(for item: Item) -> CGSize { 38 | return CGSize(width: 125, height: 160) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Example/Hex/Hex/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarHidden 32 | 33 | UIViewControllerBasedStatusBarAppearance 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Example/Hex/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform :ios, '9.0' 4 | 5 | use_frameworks! 6 | inhibit_all_warnings! 7 | 8 | target 'Hex' 9 | 10 | pod 'Hue', path: '../../' 11 | pod 'Imaginary', git: 'https://github.com/hyperoslo/Imaginary' 12 | pod 'Cache', git: 'https://github.com/hyperoslo/Cache' 13 | pod 'Spots', git: 'https://github.com/hyperoslo/Spots' 14 | pod 'Sugar', git: 'https://github.com/hyperoslo/Sugar' 15 | pod 'Tailor' 16 | -------------------------------------------------------------------------------- /Example/Hex/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Cache (3.3.0): 3 | - SwiftHash (~> 1.4.0) 4 | - Hue (2.0.1) 5 | - Imaginary (2.0.0): 6 | - Cache (~> 3.0) 7 | - Spots (6.0.3): 8 | - Spots/Core (= 6.0.3) 9 | - Spots/Core (6.0.3): 10 | - Cache (~> 3.0) 11 | - Tailor (~> 2.0) 12 | - Sugar (3.1.2) 13 | - SwiftHash (1.4.0) 14 | - Tailor (2.2.1) 15 | 16 | DEPENDENCIES: 17 | - Cache (from `https://github.com/hyperoslo/Cache`) 18 | - Hue (from `../../`) 19 | - Imaginary (from `https://github.com/hyperoslo/Imaginary`) 20 | - Spots (from `https://github.com/hyperoslo/Spots`) 21 | - Sugar (from `https://github.com/hyperoslo/Sugar`) 22 | - Tailor 23 | 24 | EXTERNAL SOURCES: 25 | Cache: 26 | :git: https://github.com/hyperoslo/Cache 27 | Hue: 28 | :path: "../../" 29 | Imaginary: 30 | :git: https://github.com/hyperoslo/Imaginary 31 | Spots: 32 | :git: https://github.com/hyperoslo/Spots 33 | Sugar: 34 | :git: https://github.com/hyperoslo/Sugar 35 | 36 | CHECKOUT OPTIONS: 37 | Cache: 38 | :commit: 4699caf4a994996840826a504270fb1ea6ac0a4f 39 | :git: https://github.com/hyperoslo/Cache 40 | Imaginary: 41 | :commit: 3176aad7a2834a966074f859fd133497532dd4d9 42 | :git: https://github.com/hyperoslo/Imaginary 43 | Spots: 44 | :commit: b99fce2737a2380fb516f1355c70ac5d4e85b356 45 | :git: https://github.com/hyperoslo/Spots 46 | Sugar: 47 | :commit: 60dfbe15325ef31cce29db4b59db7e7590c095fa 48 | :git: https://github.com/hyperoslo/Sugar 49 | 50 | SPEC CHECKSUMS: 51 | Cache: adbacf2672fbc9d48f552e03bbd4916510c39ac0 52 | Hue: ab7efb15270e0bc764f2f468aa6f3f2728d52f2b 53 | Imaginary: 642c6eb34ff2bd52404a70044599a8e2693e1e44 54 | Spots: ed7d2d6a47de7a7a0a0ed83a9b9f4484f76dc418 55 | Sugar: 41f2efa0244806f524ff2d77c951a6a43e81a0f3 56 | SwiftHash: acf0f29032309a5c7a7f625595eade1aca97aca2 57 | Tailor: caabfebed676fab6e00c0c173e05294ccf89861e 58 | 59 | PODFILE CHECKSUM: 3c397b0fa0d19e538ffbf5f81c252404517a4007 60 | 61 | COCOAPODS: 1.2.1 62 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [zenangst] 2 | -------------------------------------------------------------------------------- /Hue.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Hue" 3 | s.summary = "The all-in-one coloring utility that you'll ever need." 4 | s.version = "5.0.1" 5 | s.homepage = "https://github.com/zenangst/Hue" 6 | s.license = 'MIT' 7 | s.author = { "Christoffer Winterkvist" => "christoffer@winterkvist.com" } 8 | s.source = { :git => "https://github.com/zenangst/Hue.git", :tag => s.version.to_s } 9 | s.social_media_url = 'https://twitter.com/zenangst' 10 | 11 | s.requires_arc = true 12 | 13 | s.ios.deployment_target = '8.0' 14 | s.ios.source_files = 'Source/iOS+tvOS/**/*' 15 | s.ios.frameworks = 'UIKit' 16 | 17 | s.tvos.deployment_target = '9.0' 18 | s.tvos.source_files = 'Source/iOS+tvOS/**/*' 19 | s.tvos.frameworks = 'UIKit' 20 | 21 | s.osx.deployment_target = '10.11' 22 | s.osx.source_files = 'Source/macOS/**/*' 23 | s.osx.frameworks = 'AppKit' 24 | 25 | s.pod_target_xcconfig = { 'SWIFT_VERSION' => '5.0' } 26 | end 27 | -------------------------------------------------------------------------------- /Hue.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3868879B1C8343D0005A8868 /* Hue.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 386887911C8343CF005A8868 /* Hue.framework */; }; 11 | 386887AC1C83442A005A8868 /* NSColor+Hue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386887AA1C83442A005A8868 /* NSColor+Hue.swift */; }; 12 | 386887AE1C83442A005A8868 /* NSImage+Hue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386887AB1C83442A005A8868 /* NSImage+Hue.swift */; }; 13 | 386887B91C834591005A8868 /* NSColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386887B71C834591005A8868 /* NSColorTests.swift */; }; 14 | 386887BA1C834591005A8868 /* NSImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386887B81C834591005A8868 /* NSImageTests.swift */; }; 15 | B53E39A81CA177C900EB1EEE /* Hue.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B53E399E1CA177C900EB1EEE /* Hue.framework */; }; 16 | B53E39B51CA1793300EB1EEE /* UIColor+Hue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EEA2261C3EB008000F8F1B /* UIColor+Hue.swift */; }; 17 | B53E39B61CA1793700EB1EEE /* UIImage+Hue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EEA2271C3EB008000F8F1B /* UIImage+Hue.swift */; }; 18 | B53E39B71CA179A300EB1EEE /* UIColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EEA2151C3EAE01000F8F1B /* UIColorTests.swift */; }; 19 | B53E39B81CA179A700EB1EEE /* UIImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EEA2161C3EAE01000F8F1B /* UIImageTests.swift */; }; 20 | D2007E861F792D7E00205EF5 /* Random Access Memories.png in Resources */ = {isa = PBXBuildFile; fileRef = D2007E851F792D7E00205EF5 /* Random Access Memories.png */; }; 21 | D2007E871F792D7E00205EF5 /* Random Access Memories.png in Resources */ = {isa = PBXBuildFile; fileRef = D2007E851F792D7E00205EF5 /* Random Access Memories.png */; }; 22 | D2007E881F792D7E00205EF5 /* Random Access Memories.png in Resources */ = {isa = PBXBuildFile; fileRef = D2007E851F792D7E00205EF5 /* Random Access Memories.png */; }; 23 | D528621D1C3EAC1D00AD11AD /* Hue.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D52862121C3EAC1D00AD11AD /* Hue.framework */; }; 24 | D5EEA2221C3EAE25000F8F1B /* UIColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EEA2151C3EAE01000F8F1B /* UIColorTests.swift */; }; 25 | D5EEA2231C3EAE29000F8F1B /* UIImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EEA2161C3EAE01000F8F1B /* UIImageTests.swift */; }; 26 | D5EEA2281C3EB008000F8F1B /* UIColor+Hue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EEA2261C3EB008000F8F1B /* UIColor+Hue.swift */; }; 27 | D5EEA2291C3EB008000F8F1B /* UIImage+Hue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EEA2271C3EB008000F8F1B /* UIImage+Hue.swift */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXContainerItemProxy section */ 31 | 3868879C1C8343D0005A8868 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = D52862091C3EAC1D00AD11AD /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 386887901C8343CF005A8868; 36 | remoteInfo = "Hue-Mac"; 37 | }; 38 | B53E39A91CA177C900EB1EEE /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = D52862091C3EAC1D00AD11AD /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = B53E399D1CA177C900EB1EEE; 43 | remoteInfo = "Hue-tvOS"; 44 | }; 45 | D528621E1C3EAC1D00AD11AD /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = D52862091C3EAC1D00AD11AD /* Project object */; 48 | proxyType = 1; 49 | remoteGlobalIDString = D52862111C3EAC1D00AD11AD; 50 | remoteInfo = Hue; 51 | }; 52 | /* End PBXContainerItemProxy section */ 53 | 54 | /* Begin PBXFileReference section */ 55 | 386887911C8343CF005A8868 /* Hue.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Hue.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 3868879A1C8343D0005A8868 /* Hue-macOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Hue-macOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 386887AA1C83442A005A8868 /* NSColor+Hue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSColor+Hue.swift"; sourceTree = ""; }; 58 | 386887AB1C83442A005A8868 /* NSImage+Hue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSImage+Hue.swift"; sourceTree = ""; }; 59 | 386887B21C834567005A8868 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | 386887B71C834591005A8868 /* NSColorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = NSColorTests.swift; sourceTree = ""; tabWidth = 2; }; 61 | 386887B81C834591005A8868 /* NSImageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSImageTests.swift; sourceTree = ""; }; 62 | B53E399E1CA177C900EB1EEE /* Hue.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Hue.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | B53E39A71CA177C900EB1EEE /* Hue-tvOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Hue-tvOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | BD2D8C5E21EDF05500656C65 /* Hue.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = Hue.podspec; sourceTree = ""; }; 65 | BD2D8C6021EDF18100656C65 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | BD2D8C6221EDF19200656C65 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 67 | D2007E7F1F792D3D00205EF5 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 68 | D2007E801F792D3D00205EF5 /* Info-macOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; }; 69 | D2007E811F792D3D00205EF5 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; 70 | D2007E851F792D7E00205EF5 /* Random Access Memories.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Random Access Memories.png"; sourceTree = ""; }; 71 | D52862121C3EAC1D00AD11AD /* Hue.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Hue.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | D528621C1C3EAC1D00AD11AD /* Hue-iOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Hue-iOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | D5EEA2151C3EAE01000F8F1B /* UIColorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = UIColorTests.swift; sourceTree = ""; tabWidth = 2; }; 74 | D5EEA2161C3EAE01000F8F1B /* UIImageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageTests.swift; sourceTree = ""; }; 75 | D5EEA2261C3EB008000F8F1B /* UIColor+Hue.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = "UIColor+Hue.swift"; sourceTree = ""; tabWidth = 2; }; 76 | D5EEA2271C3EB008000F8F1B /* UIImage+Hue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Hue.swift"; sourceTree = ""; }; 77 | /* End PBXFileReference section */ 78 | 79 | /* Begin PBXFrameworksBuildPhase section */ 80 | 3868878D1C8343CF005A8868 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | 386887971C8343D0005A8868 /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | 3868879B1C8343D0005A8868 /* Hue.framework in Frameworks */, 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | B53E399A1CA177C900EB1EEE /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | B53E39A41CA177C900EB1EEE /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | B53E39A81CA177C900EB1EEE /* Hue.framework in Frameworks */, 107 | ); 108 | runOnlyForDeploymentPostprocessing = 0; 109 | }; 110 | D528620E1C3EAC1D00AD11AD /* Frameworks */ = { 111 | isa = PBXFrameworksBuildPhase; 112 | buildActionMask = 2147483647; 113 | files = ( 114 | ); 115 | runOnlyForDeploymentPostprocessing = 0; 116 | }; 117 | D52862191C3EAC1D00AD11AD /* Frameworks */ = { 118 | isa = PBXFrameworksBuildPhase; 119 | buildActionMask = 2147483647; 120 | files = ( 121 | D528621D1C3EAC1D00AD11AD /* Hue.framework in Frameworks */, 122 | ); 123 | runOnlyForDeploymentPostprocessing = 0; 124 | }; 125 | /* End PBXFrameworksBuildPhase section */ 126 | 127 | /* Begin PBXGroup section */ 128 | 386887A91C83442A005A8868 /* macOS */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 386887AA1C83442A005A8868 /* NSColor+Hue.swift */, 132 | 386887AB1C83442A005A8868 /* NSImage+Hue.swift */, 133 | ); 134 | path = macOS; 135 | sourceTree = ""; 136 | }; 137 | 386887B01C834567005A8868 /* macOS */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 386887B71C834591005A8868 /* NSColorTests.swift */, 141 | 386887B81C834591005A8868 /* NSImageTests.swift */, 142 | 386887B21C834567005A8868 /* Info.plist */, 143 | ); 144 | path = macOS; 145 | sourceTree = ""; 146 | }; 147 | BD2D8C5F21EDF18100656C65 /* iOS */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | BD2D8C6021EDF18100656C65 /* Info.plist */, 151 | ); 152 | path = iOS; 153 | sourceTree = ""; 154 | }; 155 | BD2D8C6121EDF19200656C65 /* tvOS */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | BD2D8C6221EDF19200656C65 /* Info.plist */, 159 | ); 160 | path = tvOS; 161 | sourceTree = ""; 162 | }; 163 | D2007E7E1F792D3D00205EF5 /* Info */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | D2007E7F1F792D3D00205EF5 /* Info-iOS.plist */, 167 | D2007E801F792D3D00205EF5 /* Info-macOS.plist */, 168 | D2007E811F792D3D00205EF5 /* Info-tvOS.plist */, 169 | ); 170 | path = Info; 171 | sourceTree = ""; 172 | }; 173 | D2007E841F792D7E00205EF5 /* Assets */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | D2007E851F792D7E00205EF5 /* Random Access Memories.png */, 177 | ); 178 | path = Assets; 179 | sourceTree = ""; 180 | }; 181 | D52862081C3EAC1D00AD11AD = { 182 | isa = PBXGroup; 183 | children = ( 184 | BD2D8C5E21EDF05500656C65 /* Hue.podspec */, 185 | D2007E7E1F792D3D00205EF5 /* Info */, 186 | D5EEA2121C3EAE01000F8F1B /* Tests */, 187 | D5EEA2241C3EB008000F8F1B /* Source */, 188 | D52862131C3EAC1D00AD11AD /* Products */, 189 | ); 190 | sourceTree = ""; 191 | }; 192 | D52862131C3EAC1D00AD11AD /* Products */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | D52862121C3EAC1D00AD11AD /* Hue.framework */, 196 | D528621C1C3EAC1D00AD11AD /* Hue-iOS-Tests.xctest */, 197 | 386887911C8343CF005A8868 /* Hue.framework */, 198 | 3868879A1C8343D0005A8868 /* Hue-macOSTests.xctest */, 199 | B53E399E1CA177C900EB1EEE /* Hue.framework */, 200 | B53E39A71CA177C900EB1EEE /* Hue-tvOS-Tests.xctest */, 201 | ); 202 | name = Products; 203 | sourceTree = ""; 204 | }; 205 | D5EEA2121C3EAE01000F8F1B /* Tests */ = { 206 | isa = PBXGroup; 207 | children = ( 208 | D2007E841F792D7E00205EF5 /* Assets */, 209 | BD2D8C5F21EDF18100656C65 /* iOS */, 210 | D5EEA2131C3EAE01000F8F1B /* iOS+tvOS */, 211 | 386887B01C834567005A8868 /* macOS */, 212 | BD2D8C6121EDF19200656C65 /* tvOS */, 213 | ); 214 | path = Tests; 215 | sourceTree = ""; 216 | }; 217 | D5EEA2131C3EAE01000F8F1B /* iOS+tvOS */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | D5EEA2151C3EAE01000F8F1B /* UIColorTests.swift */, 221 | D5EEA2161C3EAE01000F8F1B /* UIImageTests.swift */, 222 | ); 223 | path = "iOS+tvOS"; 224 | sourceTree = ""; 225 | }; 226 | D5EEA2241C3EB008000F8F1B /* Source */ = { 227 | isa = PBXGroup; 228 | children = ( 229 | 386887A91C83442A005A8868 /* macOS */, 230 | D5EEA2251C3EB008000F8F1B /* iOS+tvOS */, 231 | ); 232 | path = Source; 233 | sourceTree = ""; 234 | }; 235 | D5EEA2251C3EB008000F8F1B /* iOS+tvOS */ = { 236 | isa = PBXGroup; 237 | children = ( 238 | D5EEA2261C3EB008000F8F1B /* UIColor+Hue.swift */, 239 | D5EEA2271C3EB008000F8F1B /* UIImage+Hue.swift */, 240 | ); 241 | path = "iOS+tvOS"; 242 | sourceTree = ""; 243 | }; 244 | /* End PBXGroup section */ 245 | 246 | /* Begin PBXHeadersBuildPhase section */ 247 | 3868878E1C8343CF005A8868 /* Headers */ = { 248 | isa = PBXHeadersBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | B53E399B1CA177C900EB1EEE /* Headers */ = { 255 | isa = PBXHeadersBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | D528620F1C3EAC1D00AD11AD /* Headers */ = { 262 | isa = PBXHeadersBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | }; 268 | /* End PBXHeadersBuildPhase section */ 269 | 270 | /* Begin PBXNativeTarget section */ 271 | 386887901C8343CF005A8868 /* Hue-macOS */ = { 272 | isa = PBXNativeTarget; 273 | buildConfigurationList = 386887A61C8343D0005A8868 /* Build configuration list for PBXNativeTarget "Hue-macOS" */; 274 | buildPhases = ( 275 | 3868878C1C8343CF005A8868 /* Sources */, 276 | 3868878D1C8343CF005A8868 /* Frameworks */, 277 | 3868878E1C8343CF005A8868 /* Headers */, 278 | 3868878F1C8343CF005A8868 /* Resources */, 279 | ); 280 | buildRules = ( 281 | ); 282 | dependencies = ( 283 | ); 284 | name = "Hue-macOS"; 285 | productName = "Hue-Mac"; 286 | productReference = 386887911C8343CF005A8868 /* Hue.framework */; 287 | productType = "com.apple.product-type.framework"; 288 | }; 289 | 386887991C8343D0005A8868 /* Hue-macOSTests */ = { 290 | isa = PBXNativeTarget; 291 | buildConfigurationList = 386887A71C8343D0005A8868 /* Build configuration list for PBXNativeTarget "Hue-macOSTests" */; 292 | buildPhases = ( 293 | 386887961C8343D0005A8868 /* Sources */, 294 | 386887971C8343D0005A8868 /* Frameworks */, 295 | 386887981C8343D0005A8868 /* Resources */, 296 | ); 297 | buildRules = ( 298 | ); 299 | dependencies = ( 300 | 3868879D1C8343D0005A8868 /* PBXTargetDependency */, 301 | ); 302 | name = "Hue-macOSTests"; 303 | productName = "Hue-MacTests"; 304 | productReference = 3868879A1C8343D0005A8868 /* Hue-macOSTests.xctest */; 305 | productType = "com.apple.product-type.bundle.unit-test"; 306 | }; 307 | B53E399D1CA177C900EB1EEE /* Hue-tvOS */ = { 308 | isa = PBXNativeTarget; 309 | buildConfigurationList = B53E39AF1CA177C900EB1EEE /* Build configuration list for PBXNativeTarget "Hue-tvOS" */; 310 | buildPhases = ( 311 | B53E39991CA177C900EB1EEE /* Sources */, 312 | B53E399A1CA177C900EB1EEE /* Frameworks */, 313 | B53E399B1CA177C900EB1EEE /* Headers */, 314 | B53E399C1CA177C900EB1EEE /* Resources */, 315 | ); 316 | buildRules = ( 317 | ); 318 | dependencies = ( 319 | ); 320 | name = "Hue-tvOS"; 321 | productName = "Hue-tvOS"; 322 | productReference = B53E399E1CA177C900EB1EEE /* Hue.framework */; 323 | productType = "com.apple.product-type.framework"; 324 | }; 325 | B53E39A61CA177C900EB1EEE /* Hue-tvOS-Tests */ = { 326 | isa = PBXNativeTarget; 327 | buildConfigurationList = B53E39B21CA177C900EB1EEE /* Build configuration list for PBXNativeTarget "Hue-tvOS-Tests" */; 328 | buildPhases = ( 329 | B53E39A31CA177C900EB1EEE /* Sources */, 330 | B53E39A41CA177C900EB1EEE /* Frameworks */, 331 | B53E39A51CA177C900EB1EEE /* Resources */, 332 | ); 333 | buildRules = ( 334 | ); 335 | dependencies = ( 336 | B53E39AA1CA177C900EB1EEE /* PBXTargetDependency */, 337 | ); 338 | name = "Hue-tvOS-Tests"; 339 | productName = "Hue-tvOSTests"; 340 | productReference = B53E39A71CA177C900EB1EEE /* Hue-tvOS-Tests.xctest */; 341 | productType = "com.apple.product-type.bundle.unit-test"; 342 | }; 343 | D52862111C3EAC1D00AD11AD /* Hue-iOS */ = { 344 | isa = PBXNativeTarget; 345 | buildConfigurationList = D52862261C3EAC1D00AD11AD /* Build configuration list for PBXNativeTarget "Hue-iOS" */; 346 | buildPhases = ( 347 | D528620D1C3EAC1D00AD11AD /* Sources */, 348 | D528620E1C3EAC1D00AD11AD /* Frameworks */, 349 | D528620F1C3EAC1D00AD11AD /* Headers */, 350 | D52862101C3EAC1D00AD11AD /* Resources */, 351 | ); 352 | buildRules = ( 353 | ); 354 | dependencies = ( 355 | ); 356 | name = "Hue-iOS"; 357 | productName = Hue; 358 | productReference = D52862121C3EAC1D00AD11AD /* Hue.framework */; 359 | productType = "com.apple.product-type.framework"; 360 | }; 361 | D528621B1C3EAC1D00AD11AD /* Hue-iOS-Tests */ = { 362 | isa = PBXNativeTarget; 363 | buildConfigurationList = D52862291C3EAC1D00AD11AD /* Build configuration list for PBXNativeTarget "Hue-iOS-Tests" */; 364 | buildPhases = ( 365 | D52862181C3EAC1D00AD11AD /* Sources */, 366 | D52862191C3EAC1D00AD11AD /* Frameworks */, 367 | D528621A1C3EAC1D00AD11AD /* Resources */, 368 | ); 369 | buildRules = ( 370 | ); 371 | dependencies = ( 372 | D528621F1C3EAC1D00AD11AD /* PBXTargetDependency */, 373 | ); 374 | name = "Hue-iOS-Tests"; 375 | productName = HueTests; 376 | productReference = D528621C1C3EAC1D00AD11AD /* Hue-iOS-Tests.xctest */; 377 | productType = "com.apple.product-type.bundle.unit-test"; 378 | }; 379 | /* End PBXNativeTarget section */ 380 | 381 | /* Begin PBXProject section */ 382 | D52862091C3EAC1D00AD11AD /* Project object */ = { 383 | isa = PBXProject; 384 | attributes = { 385 | LastSwiftUpdateCheck = 0720; 386 | LastUpgradeCheck = 1020; 387 | ORGANIZATIONNAME = "Hyper Interaktiv AS"; 388 | TargetAttributes = { 389 | 386887901C8343CF005A8868 = { 390 | CreatedOnToolsVersion = 7.2.1; 391 | LastSwiftMigration = 0800; 392 | }; 393 | 386887991C8343D0005A8868 = { 394 | CreatedOnToolsVersion = 7.2.1; 395 | LastSwiftMigration = 0800; 396 | }; 397 | B53E399D1CA177C900EB1EEE = { 398 | CreatedOnToolsVersion = 7.2.1; 399 | LastSwiftMigration = 0800; 400 | }; 401 | B53E39A61CA177C900EB1EEE = { 402 | CreatedOnToolsVersion = 7.2.1; 403 | LastSwiftMigration = 0800; 404 | }; 405 | D52862111C3EAC1D00AD11AD = { 406 | CreatedOnToolsVersion = 7.2; 407 | LastSwiftMigration = 1020; 408 | }; 409 | D528621B1C3EAC1D00AD11AD = { 410 | CreatedOnToolsVersion = 7.2; 411 | LastSwiftMigration = 1020; 412 | }; 413 | }; 414 | }; 415 | buildConfigurationList = D528620C1C3EAC1D00AD11AD /* Build configuration list for PBXProject "Hue" */; 416 | compatibilityVersion = "Xcode 3.2"; 417 | developmentRegion = en; 418 | hasScannedForEncodings = 0; 419 | knownRegions = ( 420 | en, 421 | Base, 422 | ); 423 | mainGroup = D52862081C3EAC1D00AD11AD; 424 | productRefGroup = D52862131C3EAC1D00AD11AD /* Products */; 425 | projectDirPath = ""; 426 | projectRoot = ""; 427 | targets = ( 428 | D52862111C3EAC1D00AD11AD /* Hue-iOS */, 429 | D528621B1C3EAC1D00AD11AD /* Hue-iOS-Tests */, 430 | 386887901C8343CF005A8868 /* Hue-macOS */, 431 | 386887991C8343D0005A8868 /* Hue-macOSTests */, 432 | B53E399D1CA177C900EB1EEE /* Hue-tvOS */, 433 | B53E39A61CA177C900EB1EEE /* Hue-tvOS-Tests */, 434 | ); 435 | }; 436 | /* End PBXProject section */ 437 | 438 | /* Begin PBXResourcesBuildPhase section */ 439 | 3868878F1C8343CF005A8868 /* Resources */ = { 440 | isa = PBXResourcesBuildPhase; 441 | buildActionMask = 2147483647; 442 | files = ( 443 | ); 444 | runOnlyForDeploymentPostprocessing = 0; 445 | }; 446 | 386887981C8343D0005A8868 /* Resources */ = { 447 | isa = PBXResourcesBuildPhase; 448 | buildActionMask = 2147483647; 449 | files = ( 450 | D2007E871F792D7E00205EF5 /* Random Access Memories.png in Resources */, 451 | ); 452 | runOnlyForDeploymentPostprocessing = 0; 453 | }; 454 | B53E399C1CA177C900EB1EEE /* Resources */ = { 455 | isa = PBXResourcesBuildPhase; 456 | buildActionMask = 2147483647; 457 | files = ( 458 | ); 459 | runOnlyForDeploymentPostprocessing = 0; 460 | }; 461 | B53E39A51CA177C900EB1EEE /* Resources */ = { 462 | isa = PBXResourcesBuildPhase; 463 | buildActionMask = 2147483647; 464 | files = ( 465 | D2007E881F792D7E00205EF5 /* Random Access Memories.png in Resources */, 466 | ); 467 | runOnlyForDeploymentPostprocessing = 0; 468 | }; 469 | D52862101C3EAC1D00AD11AD /* Resources */ = { 470 | isa = PBXResourcesBuildPhase; 471 | buildActionMask = 2147483647; 472 | files = ( 473 | ); 474 | runOnlyForDeploymentPostprocessing = 0; 475 | }; 476 | D528621A1C3EAC1D00AD11AD /* Resources */ = { 477 | isa = PBXResourcesBuildPhase; 478 | buildActionMask = 2147483647; 479 | files = ( 480 | D2007E861F792D7E00205EF5 /* Random Access Memories.png in Resources */, 481 | ); 482 | runOnlyForDeploymentPostprocessing = 0; 483 | }; 484 | /* End PBXResourcesBuildPhase section */ 485 | 486 | /* Begin PBXSourcesBuildPhase section */ 487 | 3868878C1C8343CF005A8868 /* Sources */ = { 488 | isa = PBXSourcesBuildPhase; 489 | buildActionMask = 2147483647; 490 | files = ( 491 | 386887AC1C83442A005A8868 /* NSColor+Hue.swift in Sources */, 492 | 386887AE1C83442A005A8868 /* NSImage+Hue.swift in Sources */, 493 | ); 494 | runOnlyForDeploymentPostprocessing = 0; 495 | }; 496 | 386887961C8343D0005A8868 /* Sources */ = { 497 | isa = PBXSourcesBuildPhase; 498 | buildActionMask = 2147483647; 499 | files = ( 500 | 386887B91C834591005A8868 /* NSColorTests.swift in Sources */, 501 | 386887BA1C834591005A8868 /* NSImageTests.swift in Sources */, 502 | ); 503 | runOnlyForDeploymentPostprocessing = 0; 504 | }; 505 | B53E39991CA177C900EB1EEE /* Sources */ = { 506 | isa = PBXSourcesBuildPhase; 507 | buildActionMask = 2147483647; 508 | files = ( 509 | B53E39B51CA1793300EB1EEE /* UIColor+Hue.swift in Sources */, 510 | B53E39B61CA1793700EB1EEE /* UIImage+Hue.swift in Sources */, 511 | ); 512 | runOnlyForDeploymentPostprocessing = 0; 513 | }; 514 | B53E39A31CA177C900EB1EEE /* Sources */ = { 515 | isa = PBXSourcesBuildPhase; 516 | buildActionMask = 2147483647; 517 | files = ( 518 | B53E39B71CA179A300EB1EEE /* UIColorTests.swift in Sources */, 519 | B53E39B81CA179A700EB1EEE /* UIImageTests.swift in Sources */, 520 | ); 521 | runOnlyForDeploymentPostprocessing = 0; 522 | }; 523 | D528620D1C3EAC1D00AD11AD /* Sources */ = { 524 | isa = PBXSourcesBuildPhase; 525 | buildActionMask = 2147483647; 526 | files = ( 527 | D5EEA2291C3EB008000F8F1B /* UIImage+Hue.swift in Sources */, 528 | D5EEA2281C3EB008000F8F1B /* UIColor+Hue.swift in Sources */, 529 | ); 530 | runOnlyForDeploymentPostprocessing = 0; 531 | }; 532 | D52862181C3EAC1D00AD11AD /* Sources */ = { 533 | isa = PBXSourcesBuildPhase; 534 | buildActionMask = 2147483647; 535 | files = ( 536 | D5EEA2221C3EAE25000F8F1B /* UIColorTests.swift in Sources */, 537 | D5EEA2231C3EAE29000F8F1B /* UIImageTests.swift in Sources */, 538 | ); 539 | runOnlyForDeploymentPostprocessing = 0; 540 | }; 541 | /* End PBXSourcesBuildPhase section */ 542 | 543 | /* Begin PBXTargetDependency section */ 544 | 3868879D1C8343D0005A8868 /* PBXTargetDependency */ = { 545 | isa = PBXTargetDependency; 546 | target = 386887901C8343CF005A8868 /* Hue-macOS */; 547 | targetProxy = 3868879C1C8343D0005A8868 /* PBXContainerItemProxy */; 548 | }; 549 | B53E39AA1CA177C900EB1EEE /* PBXTargetDependency */ = { 550 | isa = PBXTargetDependency; 551 | target = B53E399D1CA177C900EB1EEE /* Hue-tvOS */; 552 | targetProxy = B53E39A91CA177C900EB1EEE /* PBXContainerItemProxy */; 553 | }; 554 | D528621F1C3EAC1D00AD11AD /* PBXTargetDependency */ = { 555 | isa = PBXTargetDependency; 556 | target = D52862111C3EAC1D00AD11AD /* Hue-iOS */; 557 | targetProxy = D528621E1C3EAC1D00AD11AD /* PBXContainerItemProxy */; 558 | }; 559 | /* End PBXTargetDependency section */ 560 | 561 | /* Begin XCBuildConfiguration section */ 562 | 386887A21C8343D0005A8868 /* Debug */ = { 563 | isa = XCBuildConfiguration; 564 | buildSettings = { 565 | APPLICATION_EXTENSION_API_ONLY = YES; 566 | CODE_SIGN_IDENTITY = ""; 567 | COMBINE_HIDPI_IMAGES = YES; 568 | DEFINES_MODULE = YES; 569 | DYLIB_COMPATIBILITY_VERSION = 1; 570 | DYLIB_CURRENT_VERSION = 1; 571 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 572 | FRAMEWORK_VERSION = A; 573 | INFOPLIST_FILE = "$(SRCROOT)/Info/Info-macOS.plist"; 574 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 575 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 576 | MACOSX_DEPLOYMENT_TARGET = 10.11; 577 | PRODUCT_BUNDLE_IDENTIFIER = "com.OHF.Hue-Mac"; 578 | PRODUCT_NAME = Hue; 579 | SDKROOT = macosx; 580 | SKIP_INSTALL = YES; 581 | SWIFT_VERSION = 5.0; 582 | }; 583 | name = Debug; 584 | }; 585 | 386887A31C8343D0005A8868 /* Release */ = { 586 | isa = XCBuildConfiguration; 587 | buildSettings = { 588 | APPLICATION_EXTENSION_API_ONLY = YES; 589 | CODE_SIGN_IDENTITY = ""; 590 | COMBINE_HIDPI_IMAGES = YES; 591 | DEFINES_MODULE = YES; 592 | DYLIB_COMPATIBILITY_VERSION = 1; 593 | DYLIB_CURRENT_VERSION = 1; 594 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 595 | FRAMEWORK_VERSION = A; 596 | INFOPLIST_FILE = "$(SRCROOT)/Info/Info-macOS.plist"; 597 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 598 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 599 | MACOSX_DEPLOYMENT_TARGET = 10.11; 600 | PRODUCT_BUNDLE_IDENTIFIER = "com.OHF.Hue-Mac"; 601 | PRODUCT_NAME = Hue; 602 | SDKROOT = macosx; 603 | SKIP_INSTALL = YES; 604 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 605 | SWIFT_VERSION = 5.0; 606 | }; 607 | name = Release; 608 | }; 609 | 386887A41C8343D0005A8868 /* Debug */ = { 610 | isa = XCBuildConfiguration; 611 | buildSettings = { 612 | CODE_SIGN_IDENTITY = "-"; 613 | COMBINE_HIDPI_IMAGES = YES; 614 | FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/**"; 615 | INFOPLIST_FILE = "$(SRCROOT)/Tests/macOS/Info.plist"; 616 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 617 | MACOSX_DEPLOYMENT_TARGET = 10.11; 618 | PRODUCT_BUNDLE_IDENTIFIER = com.zenangst.HueTests; 619 | PRODUCT_NAME = "$(TARGET_NAME)"; 620 | SDKROOT = macosx; 621 | SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; 622 | SWIFT_VERSION = 5.0; 623 | }; 624 | name = Debug; 625 | }; 626 | 386887A51C8343D0005A8868 /* Release */ = { 627 | isa = XCBuildConfiguration; 628 | buildSettings = { 629 | CODE_SIGN_IDENTITY = "-"; 630 | COMBINE_HIDPI_IMAGES = YES; 631 | FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/**"; 632 | INFOPLIST_FILE = "$(SRCROOT)/Tests/macOS/Info.plist"; 633 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 634 | MACOSX_DEPLOYMENT_TARGET = 10.11; 635 | PRODUCT_BUNDLE_IDENTIFIER = com.zenangst.HueTests; 636 | PRODUCT_NAME = "$(TARGET_NAME)"; 637 | SDKROOT = macosx; 638 | SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; 639 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 640 | SWIFT_VERSION = 5.0; 641 | }; 642 | name = Release; 643 | }; 644 | B53E39B01CA177C900EB1EEE /* Debug */ = { 645 | isa = XCBuildConfiguration; 646 | buildSettings = { 647 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 648 | DEFINES_MODULE = YES; 649 | DYLIB_COMPATIBILITY_VERSION = 1; 650 | DYLIB_CURRENT_VERSION = 1; 651 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 652 | INFOPLIST_FILE = "$(SRCROOT)/Info/Info-tvOS.plist"; 653 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 654 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 655 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Hue; 656 | PRODUCT_NAME = Hue; 657 | SDKROOT = appletvos; 658 | SKIP_INSTALL = YES; 659 | SWIFT_VERSION = 5.0; 660 | TARGETED_DEVICE_FAMILY = 3; 661 | TVOS_DEPLOYMENT_TARGET = 9.0; 662 | }; 663 | name = Debug; 664 | }; 665 | B53E39B11CA177C900EB1EEE /* Release */ = { 666 | isa = XCBuildConfiguration; 667 | buildSettings = { 668 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 669 | DEFINES_MODULE = YES; 670 | DYLIB_COMPATIBILITY_VERSION = 1; 671 | DYLIB_CURRENT_VERSION = 1; 672 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 673 | INFOPLIST_FILE = "$(SRCROOT)/Info/Info-tvOS.plist"; 674 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 675 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 676 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Hue; 677 | PRODUCT_NAME = Hue; 678 | SDKROOT = appletvos; 679 | SKIP_INSTALL = YES; 680 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 681 | SWIFT_VERSION = 5.0; 682 | TARGETED_DEVICE_FAMILY = 3; 683 | TVOS_DEPLOYMENT_TARGET = 9.0; 684 | }; 685 | name = Release; 686 | }; 687 | B53E39B31CA177C900EB1EEE /* Debug */ = { 688 | isa = XCBuildConfiguration; 689 | buildSettings = { 690 | INFOPLIST_FILE = "$(SRCROOT)/Tests/tvOS/Info.plist"; 691 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 692 | PRODUCT_BUNDLE_IDENTIFIER = com.zenangst.HueTests; 693 | PRODUCT_NAME = "$(TARGET_NAME)"; 694 | SDKROOT = appletvos; 695 | SWIFT_VERSION = 5.0; 696 | TVOS_DEPLOYMENT_TARGET = 9.1; 697 | }; 698 | name = Debug; 699 | }; 700 | B53E39B41CA177C900EB1EEE /* Release */ = { 701 | isa = XCBuildConfiguration; 702 | buildSettings = { 703 | INFOPLIST_FILE = "$(SRCROOT)/Tests/tvOS/Info.plist"; 704 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 705 | PRODUCT_BUNDLE_IDENTIFIER = com.zenangst.HueTests; 706 | PRODUCT_NAME = "$(TARGET_NAME)"; 707 | SDKROOT = appletvos; 708 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 709 | SWIFT_VERSION = 5.0; 710 | TVOS_DEPLOYMENT_TARGET = 9.1; 711 | }; 712 | name = Release; 713 | }; 714 | D52862241C3EAC1D00AD11AD /* Debug */ = { 715 | isa = XCBuildConfiguration; 716 | buildSettings = { 717 | ALWAYS_SEARCH_USER_PATHS = NO; 718 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 719 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 720 | CLANG_CXX_LIBRARY = "libc++"; 721 | CLANG_ENABLE_MODULES = YES; 722 | CLANG_ENABLE_OBJC_ARC = YES; 723 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 724 | CLANG_WARN_BOOL_CONVERSION = YES; 725 | CLANG_WARN_COMMA = YES; 726 | CLANG_WARN_CONSTANT_CONVERSION = YES; 727 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 728 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 729 | CLANG_WARN_EMPTY_BODY = YES; 730 | CLANG_WARN_ENUM_CONVERSION = YES; 731 | CLANG_WARN_INFINITE_RECURSION = YES; 732 | CLANG_WARN_INT_CONVERSION = YES; 733 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 734 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 735 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 736 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 737 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 738 | CLANG_WARN_STRICT_PROTOTYPES = YES; 739 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 740 | CLANG_WARN_UNREACHABLE_CODE = YES; 741 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 742 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 743 | COPY_PHASE_STRIP = NO; 744 | CURRENT_PROJECT_VERSION = 1; 745 | DEBUG_INFORMATION_FORMAT = dwarf; 746 | ENABLE_STRICT_OBJC_MSGSEND = YES; 747 | ENABLE_TESTABILITY = YES; 748 | GCC_C_LANGUAGE_STANDARD = gnu99; 749 | GCC_DYNAMIC_NO_PIC = NO; 750 | GCC_NO_COMMON_BLOCKS = YES; 751 | GCC_OPTIMIZATION_LEVEL = 0; 752 | GCC_PREPROCESSOR_DEFINITIONS = ( 753 | "DEBUG=1", 754 | "$(inherited)", 755 | ); 756 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 757 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 758 | GCC_WARN_UNDECLARED_SELECTOR = YES; 759 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 760 | GCC_WARN_UNUSED_FUNCTION = YES; 761 | GCC_WARN_UNUSED_VARIABLE = YES; 762 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 763 | MTL_ENABLE_DEBUG_INFO = YES; 764 | ONLY_ACTIVE_ARCH = YES; 765 | SDKROOT = iphoneos; 766 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 767 | SWIFT_VERSION = 5.0; 768 | TARGETED_DEVICE_FAMILY = "1,2"; 769 | VERSIONING_SYSTEM = "apple-generic"; 770 | VERSION_INFO_PREFIX = ""; 771 | }; 772 | name = Debug; 773 | }; 774 | D52862251C3EAC1D00AD11AD /* Release */ = { 775 | isa = XCBuildConfiguration; 776 | buildSettings = { 777 | ALWAYS_SEARCH_USER_PATHS = NO; 778 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 779 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 780 | CLANG_CXX_LIBRARY = "libc++"; 781 | CLANG_ENABLE_MODULES = YES; 782 | CLANG_ENABLE_OBJC_ARC = YES; 783 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 784 | CLANG_WARN_BOOL_CONVERSION = YES; 785 | CLANG_WARN_COMMA = YES; 786 | CLANG_WARN_CONSTANT_CONVERSION = YES; 787 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 788 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 789 | CLANG_WARN_EMPTY_BODY = YES; 790 | CLANG_WARN_ENUM_CONVERSION = YES; 791 | CLANG_WARN_INFINITE_RECURSION = YES; 792 | CLANG_WARN_INT_CONVERSION = YES; 793 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 794 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 795 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 796 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 797 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 798 | CLANG_WARN_STRICT_PROTOTYPES = YES; 799 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 800 | CLANG_WARN_UNREACHABLE_CODE = YES; 801 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 802 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 803 | COPY_PHASE_STRIP = NO; 804 | CURRENT_PROJECT_VERSION = 1; 805 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 806 | ENABLE_NS_ASSERTIONS = NO; 807 | ENABLE_STRICT_OBJC_MSGSEND = YES; 808 | GCC_C_LANGUAGE_STANDARD = gnu99; 809 | GCC_NO_COMMON_BLOCKS = YES; 810 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 811 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 812 | GCC_WARN_UNDECLARED_SELECTOR = YES; 813 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 814 | GCC_WARN_UNUSED_FUNCTION = YES; 815 | GCC_WARN_UNUSED_VARIABLE = YES; 816 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 817 | MTL_ENABLE_DEBUG_INFO = NO; 818 | SDKROOT = iphoneos; 819 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 820 | SWIFT_VERSION = 5.0; 821 | TARGETED_DEVICE_FAMILY = "1,2"; 822 | VALIDATE_PRODUCT = YES; 823 | VERSIONING_SYSTEM = "apple-generic"; 824 | VERSION_INFO_PREFIX = ""; 825 | }; 826 | name = Release; 827 | }; 828 | D52862271C3EAC1D00AD11AD /* Debug */ = { 829 | isa = XCBuildConfiguration; 830 | buildSettings = { 831 | APPLICATION_EXTENSION_API_ONLY = YES; 832 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 833 | DEFINES_MODULE = YES; 834 | DYLIB_COMPATIBILITY_VERSION = 1; 835 | DYLIB_CURRENT_VERSION = 1; 836 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 837 | INFOPLIST_FILE = "$(SRCROOT)/Info/Info-iOS.plist"; 838 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 839 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 840 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 841 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Hue; 842 | PRODUCT_NAME = Hue; 843 | SKIP_INSTALL = YES; 844 | SWIFT_VERSION = 5.0; 845 | }; 846 | name = Debug; 847 | }; 848 | D52862281C3EAC1D00AD11AD /* Release */ = { 849 | isa = XCBuildConfiguration; 850 | buildSettings = { 851 | APPLICATION_EXTENSION_API_ONLY = YES; 852 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 853 | DEFINES_MODULE = YES; 854 | DYLIB_COMPATIBILITY_VERSION = 1; 855 | DYLIB_CURRENT_VERSION = 1; 856 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 857 | INFOPLIST_FILE = "$(SRCROOT)/Info/Info-iOS.plist"; 858 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 859 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 860 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 861 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Hue; 862 | PRODUCT_NAME = Hue; 863 | SKIP_INSTALL = YES; 864 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 865 | SWIFT_VERSION = 5.0; 866 | }; 867 | name = Release; 868 | }; 869 | D528622A1C3EAC1D00AD11AD /* Debug */ = { 870 | isa = XCBuildConfiguration; 871 | buildSettings = { 872 | INFOPLIST_FILE = "$(SRCROOT)/Tests/iOS/Info.plist"; 873 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 874 | PRODUCT_BUNDLE_IDENTIFIER = com.zenangst.HueTests; 875 | PRODUCT_NAME = "$(TARGET_NAME)"; 876 | SWIFT_VERSION = 5.0; 877 | }; 878 | name = Debug; 879 | }; 880 | D528622B1C3EAC1D00AD11AD /* Release */ = { 881 | isa = XCBuildConfiguration; 882 | buildSettings = { 883 | INFOPLIST_FILE = "$(SRCROOT)/Tests/iOS/Info.plist"; 884 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 885 | PRODUCT_BUNDLE_IDENTIFIER = com.zenangst.HueTests; 886 | PRODUCT_NAME = "$(TARGET_NAME)"; 887 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 888 | SWIFT_VERSION = 5.0; 889 | }; 890 | name = Release; 891 | }; 892 | /* End XCBuildConfiguration section */ 893 | 894 | /* Begin XCConfigurationList section */ 895 | 386887A61C8343D0005A8868 /* Build configuration list for PBXNativeTarget "Hue-macOS" */ = { 896 | isa = XCConfigurationList; 897 | buildConfigurations = ( 898 | 386887A21C8343D0005A8868 /* Debug */, 899 | 386887A31C8343D0005A8868 /* Release */, 900 | ); 901 | defaultConfigurationIsVisible = 0; 902 | defaultConfigurationName = Release; 903 | }; 904 | 386887A71C8343D0005A8868 /* Build configuration list for PBXNativeTarget "Hue-macOSTests" */ = { 905 | isa = XCConfigurationList; 906 | buildConfigurations = ( 907 | 386887A41C8343D0005A8868 /* Debug */, 908 | 386887A51C8343D0005A8868 /* Release */, 909 | ); 910 | defaultConfigurationIsVisible = 0; 911 | defaultConfigurationName = Release; 912 | }; 913 | B53E39AF1CA177C900EB1EEE /* Build configuration list for PBXNativeTarget "Hue-tvOS" */ = { 914 | isa = XCConfigurationList; 915 | buildConfigurations = ( 916 | B53E39B01CA177C900EB1EEE /* Debug */, 917 | B53E39B11CA177C900EB1EEE /* Release */, 918 | ); 919 | defaultConfigurationIsVisible = 0; 920 | defaultConfigurationName = Release; 921 | }; 922 | B53E39B21CA177C900EB1EEE /* Build configuration list for PBXNativeTarget "Hue-tvOS-Tests" */ = { 923 | isa = XCConfigurationList; 924 | buildConfigurations = ( 925 | B53E39B31CA177C900EB1EEE /* Debug */, 926 | B53E39B41CA177C900EB1EEE /* Release */, 927 | ); 928 | defaultConfigurationIsVisible = 0; 929 | defaultConfigurationName = Release; 930 | }; 931 | D528620C1C3EAC1D00AD11AD /* Build configuration list for PBXProject "Hue" */ = { 932 | isa = XCConfigurationList; 933 | buildConfigurations = ( 934 | D52862241C3EAC1D00AD11AD /* Debug */, 935 | D52862251C3EAC1D00AD11AD /* Release */, 936 | ); 937 | defaultConfigurationIsVisible = 0; 938 | defaultConfigurationName = Release; 939 | }; 940 | D52862261C3EAC1D00AD11AD /* Build configuration list for PBXNativeTarget "Hue-iOS" */ = { 941 | isa = XCConfigurationList; 942 | buildConfigurations = ( 943 | D52862271C3EAC1D00AD11AD /* Debug */, 944 | D52862281C3EAC1D00AD11AD /* Release */, 945 | ); 946 | defaultConfigurationIsVisible = 0; 947 | defaultConfigurationName = Release; 948 | }; 949 | D52862291C3EAC1D00AD11AD /* Build configuration list for PBXNativeTarget "Hue-iOS-Tests" */ = { 950 | isa = XCConfigurationList; 951 | buildConfigurations = ( 952 | D528622A1C3EAC1D00AD11AD /* Debug */, 953 | D528622B1C3EAC1D00AD11AD /* Release */, 954 | ); 955 | defaultConfigurationIsVisible = 0; 956 | defaultConfigurationName = Release; 957 | }; 958 | /* End XCConfigurationList section */ 959 | }; 960 | rootObject = D52862091C3EAC1D00AD11AD /* Project object */; 961 | } 962 | -------------------------------------------------------------------------------- /Hue.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Hue.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Hue.xcodeproj/xcshareddata/xcschemes/Hue-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Hue.xcodeproj/xcshareddata/xcschemes/Hue-macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Hue.xcodeproj/xcshareddata/xcschemes/Hue-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Images/cover.png -------------------------------------------------------------------------------- /Images/gradients-screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Images/gradients-screenshot.gif -------------------------------------------------------------------------------- /Images/hex-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Images/hex-screenshot.png -------------------------------------------------------------------------------- /Images/icon_v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Images/icon_v3.png -------------------------------------------------------------------------------- /Info/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Info/Info-macOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Info/Info-tvOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Licensed under the **MIT** license 2 | 3 | > Copyright (c) 2015 Hyper Interaktiv AS 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining 6 | > a copy of this software and associated documentation files (the 7 | > "Software"), to deal in the Software without restriction, including 8 | > without limitation the rights to use, copy, modify, merge, publish, 9 | > distribute, sublicense, and/or sell copies of the Software, and to 10 | > permit persons to whom the Software is furnished to do so, subject to 11 | > the following conditions: 12 | > 13 | > The above copyright notice and this permission notice shall be 14 | > included in all copies or substantial portions of the Software. 15 | > 16 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "Hue", 6 | platforms: [ 7 | .iOS(.v9), 8 | .macOS(.v10_11), 9 | .tvOS(.v9), 10 | ], 11 | products: [ 12 | .library( 13 | name: "Hue", 14 | targets: ["Hue"]), 15 | ], 16 | targets: [ 17 | .target( 18 | name: "Hue", 19 | path: "Source"), 20 | ], 21 | swiftLanguageVersions: [.v5] 22 | ) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Hue](https://github.com/hyperoslo/Hue/blob/master/Images/cover.png) 2 | 3 | Hue is the all-in-one coloring utility that you'll ever need. 4 | 5 | [![Version](https://img.shields.io/cocoapods/v/Hue.svg?style=flat)](http://cocoadocs.org/docsets/Hue) 6 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 7 | [![License](https://img.shields.io/cocoapods/l/Hue.svg?style=flat)](http://cocoadocs.org/docsets/Hue) 8 | [![Platform](https://img.shields.io/cocoapods/p/Hue.svg?style=flat)](http://cocoadocs.org/docsets/Hue) 9 | ![Swift](https://img.shields.io/badge/%20in-swift%205.0-orange.svg) 10 | 11 | ## Usage 12 | 13 | #### Hex 14 | Hue IconYou can easily use hex colors with the `init(hex:)` convenience initializer on `UIColor`. It supports the following hex formats `#ffffff`, `ffffff`, `#fff`, `fff` 15 | ```swift 16 | let white = UIColor(hex: "#ffffff") 17 | let black = UIColor(hex: "#000000") 18 | let red = UIColor(hex: "#ff0000") 19 | let blue = UIColor(hex: "#0000ff") 20 | let green = UIColor(hex: "#00ff00") 21 | let yellow = UIColor(hex: "#ffff00") 22 | ``` 23 | 24 | #### Computed color properties 25 | ```swift 26 | let white = UIColor(hex: "#ffffff") 27 | let black = UIColor(hex: "#000000") 28 | 29 | if white.isDarkColor {} // return false 30 | if white.isBlackOrWhite {} // return true 31 | ``` 32 | 33 | #### Alpha 34 | `.alpha` is a sugar for `colorWithAlphaComponent`, internally it does the exact same thing, think of it as a 35 | lipstick for your implementation. 36 | ```swift 37 | let colorWithAlpha = myColor.alpha(0.75) 38 | ``` 39 | 40 | #### Gradients 41 | You can easily create gradient layers using the `gradient()` method on arrays with `UIColor`. 42 | As an extra bonus, you can also add a transform closure if you want to modify the `CAGradientLayer`. 43 | 44 | ```swift 45 | let gradient = [UIColor.blackColor(), UIColor.orangeColor()].gradient() 46 | 47 | let secondGradient = [UIColor.blackColor(), UIColor.orangeColor()].gradient { gradient in 48 | gradient.locations = [0.25, 1.0] 49 | return gradient 50 | } 51 | ``` 52 | 53 | #### Image colors 54 | ```swift 55 | let image = UIImage(named: "My Image") 56 | let (background, primary, secondary, detail) = image.colors() 57 | ``` 58 | 59 | #### Components 60 | You can get red, green, blue, and alpha components from any UIColor by using the (red|green|blue|alpha)Component property. 61 | 62 | ```swift 63 | let myColor = UIColor(hex: "#ffafc2") 64 | let myColorBlueComponent = myColor.blueComponent 65 | let myColorGreenComponent = myColor.greenComponent 66 | let myColorRedComponent = myColor.redComponent 67 | let myColorAlphaComponent = myColor.alphaComponent 68 | ``` 69 | 70 | #### Blending 71 | ```swift 72 | let red = UIColor.redColor() 73 | let green = UIColor.greenColor() 74 | let yellow = red.addRGB(green) 75 | 76 | let desaturatedBlue = UIColor(hex: "#aaaacc") 77 | let saturatedBlue = desaturatedBlue.addHue(0.0, saturation: 1.0, brightness: 0.0, alpha: 0.0) 78 | ``` 79 | 80 | ## Supporting the project 81 | 82 | If you want to support the development of this framework, you can do so by becoming a [sponsor](https://github.com/sponsors/zenangst). ❤️ 83 | 84 | ## Examples 85 | Hex Example screenshot 86 | 87 | #### Hex 88 | This super simple example that displays a bunch of color schemes in a Carousel view. 89 | 90 | It uses hex to set the color for the schemes. It leverages from `.isDarkColor` to make the text color readable in all scenarios. 91 | 92 | The demo also features [Spots](http://github.com/hyperoslo/Spots) for rendering the Carousel view. 93 | 94 | **Example code:** 95 | 96 | ```swift 97 | let color = UIColor(hex: "#3b5998") 98 | backgroundColor = color 99 | label.textColor = color.isDark 100 | ? UIColor.whiteColor() 101 | : UIColor.darkGrayColor() 102 | ``` 103 | 104 | #### Gradients 105 | Gradients Example screenshot 106 | 107 | This examples shows how much fun you can have with combining `CAGradientLayer` with `CABasicAnimation`. 108 | 109 | It uses `.hex` for getting the colors and `.gradient()` for transforming 110 | a collection of `UIColor`'s into a `CAGradientLayer`. 111 | 112 | The demo features [Spots](http://github.com/hyperoslo/Spots) for rendering the list view and [Fakery](https://github.com/vadymmarkov/Fakery) for generating random content strings. 113 | 114 | **Extract from the demo:** 115 | ```swift 116 | lazy var gradient: CAGradientLayer = [ 117 | UIColor(hex: "#FD4340"), 118 | UIColor(hex: "#CE2BAE") 119 | ].gradient { gradient in 120 | gradient.speed = 0 121 | gradient.timeOffset = 0 122 | 123 | return gradient 124 | } 125 | ``` 126 | 127 | ## Installation 128 | 129 | **Hue** is available through [CocoaPods](http://cocoapods.org). To install 130 | it, simply add the following line to your Podfile: 131 | 132 | ```ruby 133 | pod 'Hue' 134 | ``` 135 | 136 | **Hue** is also available through [Carthage](https://github.com/Carthage/Carthage). 137 | To install just write into your Cartfile: 138 | 139 | ```ruby 140 | github "hyperoslo/Hue" 141 | ``` 142 | 143 | To install **Hue** using [Swift Package Manager](https://swift.org/package-manager) with Xcode 11, just follow the instructions at and import the platform specific library to the project: 144 | 145 | ```swift 146 | import Hue 147 | ``` 148 | 149 | ## Author 150 | 151 | [Hyper](http://hyper.no) made this with ❤️ 152 | 153 | ## Contribute 154 | 155 | We would love you to contribute to **Hue**, check the [CONTRIBUTING](https://github.com/hyperoslo/Hue/blob/master/CONTRIBUTING.md) file for more info. 156 | 157 | ## Credits 158 | 159 | Credit goes out to Panic Inc who created [ColorArt](https://github.com/panicinc/ColorArt) and [@jathu](https://github.com/jathu) for his work on [UIImageColors](https://github.com/jathu/UIImageColors) which deeply inspired the functionality behind the image color analysis. 160 | 161 | ## License 162 | 163 | **Hue** is available under the MIT license. See the LICENSE file for more info. 164 | -------------------------------------------------------------------------------- /Source/iOS+tvOS/UIColor+Hue.swift: -------------------------------------------------------------------------------- 1 | #if canImport(UIKit) 2 | import UIKit 3 | 4 | // MARK: - Color Builders 5 | 6 | public extension UIColor { 7 | /// Constructing color from hex string 8 | /// 9 | /// - Parameter hex: A hex string, can either contain # or not 10 | convenience init(hex string: String) { 11 | var hex = string.hasPrefix("#") 12 | ? String(string.dropFirst()) 13 | : string 14 | guard hex.count == 3 || hex.count == 6 15 | else { 16 | self.init(white: 1.0, alpha: 0.0) 17 | return 18 | } 19 | if hex.count == 3 { 20 | for (index, char) in hex.enumerated() { 21 | hex.insert(char, at: hex.index(hex.startIndex, offsetBy: index * 2)) 22 | } 23 | } 24 | 25 | guard let intCode = Int(hex, radix: 16) else { 26 | self.init(white: 1.0, alpha: 0.0) 27 | return 28 | } 29 | 30 | self.init( 31 | red: CGFloat((intCode >> 16) & 0xFF) / 255.0, 32 | green: CGFloat((intCode >> 8) & 0xFF) / 255.0, 33 | blue: CGFloat((intCode) & 0xFF) / 255.0, alpha: 1.0) 34 | } 35 | 36 | /// Adjust color based on saturation 37 | /// 38 | /// - Parameter minSaturation: The minimun saturation value 39 | /// - Returns: The adjusted color 40 | func color(minSaturation: CGFloat) -> UIColor { 41 | var (hue, saturation, brightness, alpha): (CGFloat, CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 0.0, 0.0) 42 | getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) 43 | 44 | return saturation < minSaturation 45 | ? UIColor(hue: hue, saturation: minSaturation, brightness: brightness, alpha: alpha) 46 | : self 47 | } 48 | 49 | /// Convenient method to change alpha value 50 | /// 51 | /// - Parameter value: The alpha value 52 | /// - Returns: The alpha adjusted color 53 | func alpha(_ value: CGFloat) -> UIColor { 54 | return withAlphaComponent(value) 55 | } 56 | } 57 | 58 | // MARK: - Helpers 59 | 60 | public extension UIColor { 61 | 62 | func hex(hashPrefix: Bool = true) -> String { 63 | var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 0.0, 0.0) 64 | getRed(&r, green: &g, blue: &b, alpha: &a) 65 | 66 | let prefix = hashPrefix ? "#" : "" 67 | 68 | return String(format: "\(prefix)%02X%02X%02X", Int(r * 255), Int(g * 255), Int(b * 255)) 69 | } 70 | 71 | internal func rgbComponents() -> [CGFloat] { 72 | var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 0.0, 0.0) 73 | getRed(&r, green: &g, blue: &b, alpha: &a) 74 | 75 | return [r, g, b] 76 | } 77 | 78 | var isDark: Bool { 79 | let RGB = rgbComponents() 80 | return (0.2126 * RGB[0] + 0.7152 * RGB[1] + 0.0722 * RGB[2]) < 0.5 81 | } 82 | 83 | var isBlackOrWhite: Bool { 84 | let RGB = rgbComponents() 85 | return (RGB[0] > 0.91 && RGB[1] > 0.91 && RGB[2] > 0.91) || (RGB[0] < 0.09 && RGB[1] < 0.09 && RGB[2] < 0.09) 86 | } 87 | 88 | var isBlack: Bool { 89 | let RGB = rgbComponents() 90 | return (RGB[0] < 0.09 && RGB[1] < 0.09 && RGB[2] < 0.09) 91 | } 92 | 93 | var isWhite: Bool { 94 | let RGB = rgbComponents() 95 | return (RGB[0] > 0.91 && RGB[1] > 0.91 && RGB[2] > 0.91) 96 | } 97 | 98 | func isDistinct(from color: UIColor) -> Bool { 99 | let bg = rgbComponents() 100 | let fg = color.rgbComponents() 101 | let threshold: CGFloat = 0.25 102 | var result = false 103 | 104 | if abs(bg[0] - fg[0]) > threshold || abs(bg[1] - fg[1]) > threshold || abs(bg[2] - fg[2]) > threshold { 105 | if abs(bg[0] - bg[1]) < 0.03 && abs(bg[0] - bg[2]) < 0.03 { 106 | if abs(fg[0] - fg[1]) < 0.03 && abs(fg[0] - fg[2]) < 0.03 { 107 | result = false 108 | } 109 | } 110 | result = true 111 | } 112 | 113 | return result 114 | } 115 | 116 | func isContrasting(with color: UIColor) -> Bool { 117 | let bg = rgbComponents() 118 | let fg = color.rgbComponents() 119 | 120 | let bgLum = 0.2126 * bg[0] + 0.7152 * bg[1] + 0.0722 * bg[2] 121 | let fgLum = 0.2126 * fg[0] + 0.7152 * fg[1] + 0.0722 * fg[2] 122 | let contrast = bgLum > fgLum 123 | ? (bgLum + 0.05) / (fgLum + 0.05) 124 | : (fgLum + 0.05) / (bgLum + 0.05) 125 | 126 | return 1.6 < contrast 127 | } 128 | 129 | } 130 | 131 | // MARK: - Gradient 132 | 133 | public extension Array where Element : UIColor { 134 | 135 | func gradient(_ transform: ((_ gradient: inout CAGradientLayer) -> CAGradientLayer)? = nil) -> CAGradientLayer { 136 | var gradient = CAGradientLayer() 137 | gradient.colors = self.map { $0.cgColor } 138 | 139 | if let transform = transform { 140 | gradient = transform(&gradient) 141 | } 142 | 143 | return gradient 144 | } 145 | } 146 | 147 | // MARK: - Components 148 | 149 | public extension UIColor { 150 | 151 | var redComponent: CGFloat { 152 | var red: CGFloat = 0 153 | getRed(&red, green: nil , blue: nil, alpha: nil) 154 | return red 155 | } 156 | 157 | var greenComponent: CGFloat { 158 | var green: CGFloat = 0 159 | getRed(nil, green: &green , blue: nil, alpha: nil) 160 | return green 161 | } 162 | 163 | var blueComponent: CGFloat { 164 | var blue: CGFloat = 0 165 | getRed(nil, green: nil , blue: &blue, alpha: nil) 166 | return blue 167 | } 168 | 169 | var alphaComponent: CGFloat { 170 | var alpha: CGFloat = 0 171 | getRed(nil, green: nil , blue: nil, alpha: &alpha) 172 | return alpha 173 | } 174 | 175 | var hueComponent: CGFloat { 176 | var hue: CGFloat = 0 177 | getHue(&hue, saturation: nil, brightness: nil, alpha: nil) 178 | return hue 179 | } 180 | 181 | var saturationComponent: CGFloat { 182 | var saturation: CGFloat = 0 183 | getHue(nil, saturation: &saturation, brightness: nil, alpha: nil) 184 | return saturation 185 | } 186 | 187 | var brightnessComponent: CGFloat { 188 | var brightness: CGFloat = 0 189 | getHue(nil, saturation: nil, brightness: &brightness, alpha: nil) 190 | return brightness 191 | } 192 | } 193 | 194 | 195 | // MARK: - Blending 196 | 197 | public extension UIColor { 198 | 199 | /**adds hue, saturation, and brightness to the HSB components of this color (self)*/ 200 | func add(hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat) -> UIColor { 201 | var (oldHue, oldSat, oldBright, oldAlpha) : (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0) 202 | getHue(&oldHue, saturation: &oldSat, brightness: &oldBright, alpha: &oldAlpha) 203 | 204 | // make sure new values doesn't overflow 205 | var newHue = oldHue + hue 206 | while newHue < 0.0 { newHue += 1.0 } 207 | while newHue > 1.0 { newHue -= 1.0 } 208 | 209 | let newBright: CGFloat = max(min(oldBright + brightness, 1.0), 0) 210 | let newSat: CGFloat = max(min(oldSat + saturation, 1.0), 0) 211 | let newAlpha: CGFloat = max(min(oldAlpha + alpha, 1.0), 0) 212 | 213 | return UIColor(hue: newHue, saturation: newSat, brightness: newBright, alpha: newAlpha) 214 | } 215 | 216 | /**adds red, green, and blue to the RGB components of this color (self)*/ 217 | func add(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) -> UIColor { 218 | var (oldRed, oldGreen, oldBlue, oldAlpha) : (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0) 219 | getRed(&oldRed, green: &oldGreen, blue: &oldBlue, alpha: &oldAlpha) 220 | // make sure new values doesn't overflow 221 | let newRed: CGFloat = max(min(oldRed + red, 1.0), 0) 222 | let newGreen: CGFloat = max(min(oldGreen + green, 1.0), 0) 223 | let newBlue: CGFloat = max(min(oldBlue + blue, 1.0), 0) 224 | let newAlpha: CGFloat = max(min(oldAlpha + alpha, 1.0), 0) 225 | return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: newAlpha) 226 | } 227 | 228 | func add(hsb color: UIColor) -> UIColor { 229 | var (h,s,b,a) : (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0) 230 | color.getHue(&h, saturation: &s, brightness: &b, alpha: &a) 231 | return self.add(hue: h, saturation: s, brightness: b, alpha: 0) 232 | } 233 | 234 | func add(rgb color: UIColor) -> UIColor { 235 | return self.add(red: color.redComponent, green: color.greenComponent, blue: color.blueComponent, alpha: 0) 236 | } 237 | 238 | func add(hsba color: UIColor) -> UIColor { 239 | var (h,s,b,a) : (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0) 240 | color.getHue(&h, saturation: &s, brightness: &b, alpha: &a) 241 | return self.add(hue: h, saturation: s, brightness: b, alpha: a) 242 | } 243 | 244 | /**adds the rgb components of two colors*/ 245 | func add(rgba color: UIColor) -> UIColor { 246 | return self.add(red: color.redComponent, green: color.greenComponent, blue: color.blueComponent, alpha: color.alphaComponent) 247 | } 248 | } 249 | #endif 250 | -------------------------------------------------------------------------------- /Source/iOS+tvOS/UIImage+Hue.swift: -------------------------------------------------------------------------------- 1 | #if canImport(UIKit) 2 | import UIKit 3 | 4 | class CountedColor { 5 | let color: UIColor 6 | let count: Int 7 | 8 | init(color: UIColor, count: Int) { 9 | self.color = color 10 | self.count = count 11 | } 12 | } 13 | 14 | extension UIImage { 15 | fileprivate func resize(to newSize: CGSize) -> UIImage { 16 | UIGraphicsBeginImageContextWithOptions(newSize, false, 2) 17 | draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)) 18 | let result = UIGraphicsGetImageFromCurrentImageContext() 19 | UIGraphicsEndImageContext() 20 | 21 | return result! 22 | } 23 | 24 | public func colors(scaleDownSize: CGSize? = nil) -> (background: UIColor, primary: UIColor, secondary: UIColor, detail: UIColor) { 25 | let cgImage: CGImage 26 | 27 | if let scaleDownSize = scaleDownSize { 28 | cgImage = resize(to: scaleDownSize).cgImage! 29 | } else { 30 | let ratio = size.width / size.height 31 | let r_width: CGFloat = 250 32 | cgImage = resize(to: CGSize(width: r_width, height: r_width / ratio)).cgImage! 33 | } 34 | 35 | let width = cgImage.width 36 | let height = cgImage.height 37 | let bytesPerPixel = 4 38 | let bytesPerRow = width * bytesPerPixel 39 | let bitsPerComponent = 8 40 | let randomColorsThreshold = Int(CGFloat(height) * 0.01) 41 | let blackColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1) 42 | let whiteColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1) 43 | let colorSpace = CGColorSpaceCreateDeviceRGB() 44 | let raw = malloc(bytesPerRow * height)! 45 | let bitmapInfo = CGImageAlphaInfo.premultipliedFirst.rawValue 46 | let context = CGContext(data: raw, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) 47 | context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height))) 48 | let data = UnsafePointer(context?.data?.assumingMemoryBound(to: UInt8.self)) 49 | let imageBackgroundColors = NSCountedSet(capacity: height) 50 | let imageColors = NSCountedSet(capacity: width * height) 51 | 52 | let sortComparator: (CountedColor, CountedColor) -> Bool = { (a, b) -> Bool in 53 | return a.count <= b.count 54 | } 55 | 56 | for x in 0..= 5 && x <= 10 { 67 | imageBackgroundColors.add(color) 68 | } 69 | 70 | imageColors.add(color) 71 | } 72 | } 73 | 74 | var sortedColors = [CountedColor]() 75 | 76 | for color in imageBackgroundColors { 77 | guard let color = color as? UIColor else { continue } 78 | 79 | let colorCount = imageBackgroundColors.count(for: color) 80 | 81 | if randomColorsThreshold <= colorCount { 82 | sortedColors.append(CountedColor(color: color, count: colorCount)) 83 | } 84 | } 85 | 86 | sortedColors.sort(by: sortComparator) 87 | 88 | var proposedEdgeColor = CountedColor(color: blackColor, count: 1) 89 | 90 | if let first = sortedColors.first { proposedEdgeColor = first } 91 | 92 | if proposedEdgeColor.color.isBlackOrWhite && !sortedColors.isEmpty { 93 | for countedColor in sortedColors where CGFloat(countedColor.count / proposedEdgeColor.count) > 0.3 { 94 | if !countedColor.color.isBlackOrWhite { 95 | proposedEdgeColor = countedColor 96 | break 97 | } 98 | } 99 | } 100 | 101 | let imageBackgroundColor = proposedEdgeColor.color 102 | let isDarkBackgound = imageBackgroundColor.isDark 103 | 104 | sortedColors.removeAll() 105 | 106 | for imageColor in imageColors { 107 | guard let imageColor = imageColor as? UIColor else { continue } 108 | 109 | let color = imageColor.color(minSaturation: 0.15) 110 | 111 | if color.isDark == !isDarkBackgound { 112 | let colorCount = imageColors.count(for: color) 113 | sortedColors.append(CountedColor(color: color, count: colorCount)) 114 | } 115 | } 116 | 117 | sortedColors.sort(by: sortComparator) 118 | 119 | var primaryColor, secondaryColor, detailColor: UIColor? 120 | 121 | for countedColor in sortedColors { 122 | let color = countedColor.color 123 | 124 | if primaryColor == nil && 125 | color.isContrasting(with: imageBackgroundColor) { 126 | primaryColor = color 127 | } else if secondaryColor == nil && 128 | primaryColor != nil && 129 | primaryColor!.isDistinct(from: color) && 130 | color.isContrasting(with: imageBackgroundColor) { 131 | secondaryColor = color 132 | } else if secondaryColor != nil && 133 | (secondaryColor!.isDistinct(from: color) && 134 | primaryColor!.isDistinct(from: color) && 135 | color.isContrasting(with: imageBackgroundColor)) { 136 | detailColor = color 137 | break 138 | } 139 | } 140 | 141 | free(raw) 142 | 143 | return ( 144 | imageBackgroundColor, 145 | primaryColor ?? (isDarkBackgound ? whiteColor : blackColor), 146 | secondaryColor ?? (isDarkBackgound ? whiteColor : blackColor), 147 | detailColor ?? (isDarkBackgound ? whiteColor : blackColor)) 148 | } 149 | 150 | public func color(at point: CGPoint, completion: @escaping (UIColor?) -> Void) { 151 | let size = self.size 152 | let cgImage = self.cgImage 153 | 154 | DispatchQueue.global(qos: .userInteractive).async { 155 | let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) 156 | guard let imgRef = cgImage, 157 | let dataProvider = imgRef.dataProvider, 158 | let dataCopy = dataProvider.data, 159 | let data = CFDataGetBytePtr(dataCopy), rect.contains(point) else { 160 | DispatchQueue.main.async { 161 | completion(nil) 162 | } 163 | return 164 | } 165 | 166 | let pixelInfo = (Int(size.width) * Int(point.y) + Int(point.x)) * 4 167 | let red = CGFloat(data[pixelInfo]) / 255.0 168 | let green = CGFloat(data[pixelInfo + 1]) / 255.0 169 | let blue = CGFloat(data[pixelInfo + 2]) / 255.0 170 | let alpha = CGFloat(data[pixelInfo + 3]) / 255.0 171 | 172 | DispatchQueue.main.async { 173 | completion(UIColor(red: red, green: green, blue: blue, alpha: alpha)) 174 | } 175 | } 176 | } 177 | } 178 | #endif 179 | -------------------------------------------------------------------------------- /Source/macOS/NSColor+Hue.swift: -------------------------------------------------------------------------------- 1 | #if canImport(AppKit) && !targetEnvironment(macCatalyst) 2 | import AppKit 3 | 4 | // MARK: - Color Builders 5 | 6 | public extension NSColor { 7 | /// Constructing color from hex string 8 | /// 9 | /// - Parameter hex: A hex string, can either contain # or not 10 | convenience init(hex string: String) { 11 | var hex = string.hasPrefix("#") 12 | ? String(string.dropFirst()) 13 | : string 14 | guard hex.count == 3 || hex.count == 6 15 | else { 16 | self.init(white: 1.0, alpha: 0.0) 17 | return 18 | } 19 | if hex.count == 3 { 20 | for (index, char) in hex.enumerated() { 21 | hex.insert(char, at: hex.index(hex.startIndex, offsetBy: index * 2)) 22 | } 23 | } 24 | 25 | guard let intCode = Int(hex, radix: 16) else { 26 | self.init(white: 1.0, alpha: 0.0) 27 | return 28 | } 29 | 30 | self.init( 31 | red: CGFloat((intCode >> 16) & 0xFF) / 255.0, 32 | green: CGFloat((intCode >> 8) & 0xFF) / 255.0, 33 | blue: CGFloat((intCode) & 0xFF) / 255.0, alpha: 1.0) 34 | } 35 | 36 | /// Adjust color based on saturation 37 | /// 38 | /// - Parameter minSaturation: The minimun saturation value 39 | /// - Returns: The adjusted color 40 | func color(minSaturation: CGFloat) -> NSColor { 41 | var (hue, saturation, brightness, alpha): (CGFloat, CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 0.0, 0.0) 42 | getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) 43 | 44 | return saturation < minSaturation 45 | ? NSColor(hue: hue, saturation: minSaturation, brightness: brightness, alpha: alpha) 46 | : self 47 | } 48 | 49 | 50 | /// Convenient method to change alpha value 51 | /// 52 | /// - Parameter value: The alpha value 53 | /// - Returns: The alpha adjusted color 54 | func alpha(_ value: CGFloat) -> NSColor { 55 | return withAlphaComponent(value) 56 | } 57 | } 58 | 59 | // MARK: - Helpers 60 | 61 | public extension NSColor { 62 | 63 | func hex(hashPrefix: Bool = true) -> String { 64 | var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 0.0, 0.0) 65 | usingColorSpace(NSColorSpace.genericRGB)!.getRed(&r, green: &g, blue: &b, alpha: &a) 66 | 67 | let prefix = hashPrefix ? "#" : "" 68 | 69 | return String(format: "\(prefix)%02X%02X%02X", Int(r * 255), Int(g * 255), Int(b * 255)) 70 | } 71 | 72 | internal func rgbComponents() -> [CGFloat] { 73 | var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0.0, 0.0, 0.0, 0.0) 74 | usingColorSpace(NSColorSpace.genericRGB)!.getRed(&r, green: &g, blue: &b, alpha: &a) 75 | 76 | return [r, g, b] 77 | } 78 | 79 | var isDark: Bool { 80 | let RGB = rgbComponents() 81 | return (0.2126 * RGB[0] + 0.7152 * RGB[1] + 0.0722 * RGB[2]) < 0.5 82 | } 83 | 84 | var isBlackOrWhite: Bool { 85 | let RGB = rgbComponents() 86 | return (RGB[0] > 0.91 && RGB[1] > 0.91 && RGB[2] > 0.91) || (RGB[0] < 0.09 && RGB[1] < 0.09 && RGB[2] < 0.09) 87 | } 88 | 89 | var isBlack: Bool { 90 | let RGB = rgbComponents() 91 | return (RGB[0] < 0.09 && RGB[1] < 0.09 && RGB[2] < 0.09) 92 | } 93 | 94 | var isWhite: Bool { 95 | let RGB = rgbComponents() 96 | return (RGB[0] > 0.91 && RGB[1] > 0.91 && RGB[2] > 0.91) 97 | } 98 | 99 | func isDistinct(from color: NSColor) -> Bool { 100 | let bg = rgbComponents() 101 | let fg = color.rgbComponents() 102 | let threshold: CGFloat = 0.25 103 | var result = false 104 | 105 | if abs(bg[0] - fg[0]) > threshold || abs(bg[1] - fg[1]) > threshold || abs(bg[2] - fg[2]) > threshold { 106 | if abs(bg[0] - bg[1]) < 0.03 && abs(bg[0] - bg[2]) < 0.03 { 107 | if abs(fg[0] - fg[1]) < 0.03 && abs(fg[0] - fg[2]) < 0.03 { 108 | result = false 109 | } 110 | } 111 | result = true 112 | } 113 | 114 | return result 115 | } 116 | 117 | func isContrasting(with color: NSColor) -> Bool { 118 | 119 | func colorLum(rgb: [CGFloat]) -> CGFloat { 120 | let r = 0.2126 * rgb[0] 121 | let g = 0.7152 * rgb[1] 122 | let b = 0.0722 * rgb[2] 123 | return r + g + b 124 | } 125 | 126 | let bgComponents = rgbComponents() 127 | let fgComponents = color.rgbComponents() 128 | 129 | let br = bgComponents[0] 130 | let bg = bgComponents[1] 131 | let bb = bgComponents[2] 132 | let fr = fgComponents[0] 133 | let fg = fgComponents[1] 134 | let fb = fgComponents[2] 135 | 136 | let bgLum = 0.2126 * br + 0.7152 * bg + 0.0722 * bb 137 | let fgLum = 0.2126 * fr + 0.7152 * fg + 0.0722 * fb 138 | let contrast = bgLum > fgLum 139 | ? (bgLum + 0.05) / (fgLum + 0.05) 140 | : (fgLum + 0.05) / (bgLum + 0.05) 141 | 142 | return 1.6 < contrast 143 | } 144 | } 145 | 146 | // MARK: - Gradient 147 | 148 | public extension Array where Element : NSColor { 149 | func gradient(_ transform: ((_ gradient: inout CAGradientLayer) -> CAGradientLayer)? = nil) -> CAGradientLayer { 150 | var gradient = CAGradientLayer() 151 | gradient.colors = self.map { $0.cgColor } 152 | 153 | if let transform = transform { 154 | gradient = transform(&gradient) 155 | } 156 | 157 | return gradient 158 | } 159 | } 160 | 161 | // MARK: - Components 162 | 163 | public extension NSColor { 164 | 165 | func getRed() -> CGFloat { 166 | if (self.colorSpace == NSColorSpace.genericGray || 167 | self.colorSpace == NSColorSpace.deviceGray) { 168 | return self.whiteComponent 169 | } 170 | 171 | var r : CGFloat = 0 172 | self.getRed(&r, green: nil , blue: nil, alpha: nil) 173 | return r 174 | } 175 | 176 | func getGreen() -> CGFloat { 177 | if (self.colorSpace == NSColorSpace.genericGray || 178 | self.colorSpace == NSColorSpace.deviceGray) { 179 | return self.whiteComponent 180 | } 181 | 182 | var g : CGFloat = 0 183 | self.getRed(nil, green: &g , blue: nil, alpha: nil) 184 | return g 185 | } 186 | 187 | func getBlue() -> CGFloat { 188 | if (self.colorSpace == NSColorSpace.genericGray || 189 | self.colorSpace == NSColorSpace.deviceGray) { 190 | return self.whiteComponent 191 | } 192 | 193 | var b : CGFloat = 0 194 | self.getRed(nil, green: nil , blue: &b, alpha: nil) 195 | return b 196 | } 197 | 198 | func getAlpha() -> CGFloat { 199 | if (self.colorSpace == NSColorSpace.genericGray || 200 | self.colorSpace == NSColorSpace.deviceGray) { 201 | return self.alphaComponent 202 | } 203 | 204 | var a : CGFloat = 0 205 | self.getRed(nil, green: nil , blue: nil, alpha: &a) 206 | return a 207 | } 208 | } 209 | 210 | // MARK: - Blending 211 | 212 | public extension NSColor { 213 | 214 | /**adds hue, saturation, and brightness to the HSB components of this color (self)*/ 215 | func add(hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat) -> NSColor { 216 | var (oldHue, oldSat, oldBright, oldAlpha) : (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0) 217 | self.getHue(&oldHue, saturation: &oldSat, brightness: &oldBright, alpha: &oldAlpha) 218 | 219 | // make sure new values doesn't overflow 220 | var newHue = oldHue + hue 221 | while newHue < 0.0 { newHue += 1.0 } 222 | while newHue > 1.0 { newHue -= 1.0 } 223 | 224 | let newBright: CGFloat = max(min(oldBright + brightness, 1.0), 0) 225 | let newSat: CGFloat = max(min(oldSat + saturation, 1.0), 0) 226 | let newAlpha: CGFloat = max(min(oldAlpha + alpha, 1.0), 0) 227 | 228 | return NSColor(hue: newHue, saturation: newBright, brightness: newSat, alpha: newAlpha) 229 | } 230 | 231 | /**adds red, green, and blue to the RGB components of this color (self)*/ 232 | func add(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) -> NSColor { 233 | // make sure new values doesn't overflow 234 | let newRed: CGFloat = max(min(self.getRed() + red, 1.0), 0) 235 | let newGreen: CGFloat = max(min(self.getGreen() + green, 1.0), 0) 236 | let newBlue: CGFloat = max(min(self.getBlue() + blue, 1.0), 0) 237 | let newAlpha: CGFloat = max(min(self.getAlpha() + alpha, 1.0), 0) 238 | return NSColor(red: newRed, green: newGreen, blue: newBlue, alpha: newAlpha) 239 | } 240 | 241 | func add(hsb color: NSColor) -> NSColor { 242 | var (h,s,b,a) : (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0) 243 | color.getHue(&h, saturation: &s, brightness: &b, alpha: &a) 244 | return self.add(hue: h, saturation: s, brightness: b, alpha: 0) 245 | } 246 | 247 | func add(rgb color: NSColor) -> NSColor { 248 | return self.add(red: color.getRed(), green: color.getGreen(), blue: color.getBlue(), alpha: 0) 249 | } 250 | 251 | func add(hsba color: NSColor) -> NSColor { 252 | var (h,s,b,a) : (CGFloat, CGFloat, CGFloat, CGFloat) = (0,0,0,0) 253 | color.getHue(&h, saturation: &s, brightness: &b, alpha: &a) 254 | return self.add(hue: h, saturation: s, brightness: b, alpha: a) 255 | } 256 | 257 | /**adds the rgb components of two colors*/ 258 | func add(rgba color: NSColor) -> NSColor { 259 | return self.add(red: color.getRed(), green: color.getGreen(), blue: color.getBlue(), alpha: color.getAlpha()) 260 | } 261 | } 262 | #endif 263 | -------------------------------------------------------------------------------- /Source/macOS/NSImage+Hue.swift: -------------------------------------------------------------------------------- 1 | #if canImport(AppKit) && !targetEnvironment(macCatalyst) 2 | import AppKit 3 | 4 | class CountedColor { 5 | let color: NSColor 6 | let count: Int 7 | 8 | init(color: NSColor, count: Int) { 9 | self.color = color 10 | self.count = count 11 | } 12 | } 13 | 14 | extension NSImage { 15 | fileprivate func resize(to newSize: CGSize) -> NSImage { 16 | guard newSize.width > 0.0 && newSize.height > 0.0 else { return NSImage() } 17 | 18 | let scaledImage = NSImage(size: newSize) 19 | scaledImage.lockFocus() 20 | let ctx = NSGraphicsContext.current 21 | ctx?.imageInterpolation = .high 22 | draw(in: NSMakeRect(0, 0, newSize.width, newSize.height), from: NSRect.zero, operation: .copy, fraction: 1) 23 | scaledImage.unlockFocus() 24 | 25 | return scaledImage 26 | } 27 | 28 | public func colors(scaleDownSize: CGSize? = nil) -> (background: NSColor, primary: NSColor, secondary: NSColor, detail: NSColor) { 29 | let cgImage: CGImage? 30 | 31 | if let scaleDownSize = scaleDownSize { 32 | let context = NSGraphicsContext.current 33 | cgImage = resize(to: scaleDownSize).cgImage(forProposedRect: nil, context: context, hints: nil) 34 | } else { 35 | let context = NSGraphicsContext.current 36 | let ratio = size.width / size.height 37 | let r_width: CGFloat = 250 38 | cgImage = resize(to: CGSize(width: r_width, height: r_width / ratio)).cgImage(forProposedRect: nil, context: context, hints: nil) 39 | } 40 | 41 | guard let resolvedImage = cgImage else { return (background: NSColor.clear, 42 | primary: NSColor.clear, 43 | secondary: NSColor.clear, 44 | detail: NSColor.clear) } 45 | 46 | let width = resolvedImage.width 47 | let height = resolvedImage.height 48 | let bytesPerPixel = 4 49 | let bytesPerRow = width * bytesPerPixel 50 | let bitsPerComponent = 8 51 | let randomColorsThreshold = Int(CGFloat(height) * 0.01) 52 | let blackColor = NSColor(red: 0, green: 0, blue: 0, alpha: 1) 53 | let whiteColor = NSColor(red: 1, green: 1, blue: 1, alpha: 1) 54 | let colorSpace = CGColorSpaceCreateDeviceRGB() 55 | let raw = malloc(bytesPerRow * height)! 56 | let bitmapInfo = CGImageAlphaInfo.premultipliedFirst.rawValue 57 | let context = CGContext(data: raw, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) 58 | context?.draw(resolvedImage, in: CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height))) 59 | let rawData = context?.data?.assumingMemoryBound(to: UInt8.self) 60 | let imageBackgroundColors = NSCountedSet(capacity: height) 61 | let imageColors = NSCountedSet(capacity: width * height) 62 | 63 | let sortComparator: (CountedColor, CountedColor) -> Bool = { (a, b) -> Bool in 64 | return a.count <= b.count 65 | } 66 | 67 | guard let data = rawData else { return (background: NSColor.clear, 68 | primary: NSColor.clear, 69 | secondary: NSColor.clear, 70 | detail: NSColor.clear) 71 | } 72 | 73 | for x in 0..= 5 && x <= 10 { 84 | imageBackgroundColors.add(color) 85 | } 86 | 87 | imageColors.add(color) 88 | } 89 | } 90 | 91 | var sortedColors = [CountedColor]() 92 | 93 | for color in imageBackgroundColors { 94 | guard let color = color as? NSColor else { continue } 95 | 96 | let colorCount = imageBackgroundColors.count(for: color) 97 | 98 | if randomColorsThreshold <= colorCount { 99 | sortedColors.append(CountedColor(color: color, count: colorCount)) 100 | } 101 | } 102 | 103 | sortedColors.sort(by: sortComparator) 104 | 105 | var proposedEdgeColor = CountedColor(color: blackColor, count: 1) 106 | 107 | if let first = sortedColors.first { proposedEdgeColor = first } 108 | 109 | if proposedEdgeColor.color.isBlackOrWhite && !sortedColors.isEmpty { 110 | for countedColor in sortedColors where CGFloat(countedColor.count / proposedEdgeColor.count) > 0.3 { 111 | if !countedColor.color.isBlackOrWhite { 112 | proposedEdgeColor = countedColor 113 | break 114 | } 115 | } 116 | } 117 | 118 | let imageBackgroundColor = proposedEdgeColor.color 119 | let isDarkBackgound = imageBackgroundColor.isDark 120 | 121 | sortedColors.removeAll() 122 | 123 | for imageColor in imageColors { 124 | guard let imageColor = imageColor as? NSColor else { continue } 125 | 126 | let color = imageColor.color(minSaturation: 0.15) 127 | 128 | if color.isDark == !isDarkBackgound { 129 | let colorCount = imageColors.count(for: color) 130 | sortedColors.append(CountedColor(color: color, count: colorCount)) 131 | } 132 | } 133 | 134 | sortedColors.sort(by: sortComparator) 135 | 136 | var primaryColor, secondaryColor, detailColor: NSColor? 137 | 138 | for countedColor in sortedColors { 139 | let color = countedColor.color 140 | 141 | if primaryColor == nil && 142 | color.isContrasting(with: imageBackgroundColor) { 143 | primaryColor = color 144 | } else if secondaryColor == nil && 145 | primaryColor != nil && 146 | primaryColor!.isDistinct(from: color) && 147 | color.isContrasting(with: imageBackgroundColor) { 148 | secondaryColor = color 149 | } else if secondaryColor != nil && 150 | (secondaryColor!.isDistinct(from: color) && 151 | primaryColor!.isDistinct(from: color) && 152 | color.isContrasting(with: imageBackgroundColor)) { 153 | detailColor = color 154 | break 155 | } 156 | } 157 | 158 | free(raw) 159 | 160 | return ( 161 | imageBackgroundColor, 162 | primaryColor ?? (isDarkBackgound ? whiteColor : blackColor), 163 | secondaryColor ?? (isDarkBackgound ? whiteColor : blackColor), 164 | detailColor ?? (isDarkBackgound ? whiteColor : blackColor)) 165 | } 166 | } 167 | #endif 168 | -------------------------------------------------------------------------------- /Tests/Assets/Random Access Memories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenangst/Hue/779143caf92ae77744cc8f4b61569ea003933944/Tests/Assets/Random Access Memories.png -------------------------------------------------------------------------------- /Tests/iOS+tvOS/UIColorTests.swift: -------------------------------------------------------------------------------- 1 | import Hue 2 | import UIKit 3 | import XCTest 4 | 5 | class UIColorTests: XCTestCase { 6 | 7 | func testHex() { 8 | let white = UIColor(hex: "#FFFFFF") 9 | let black = UIColor(hex: "000000") 10 | let red = UIColor(hex: "F00") 11 | let blue = UIColor(hex: "#00F") 12 | let green = UIColor(hex: "#00FF00") 13 | let yellow = UIColor(hex: "#FFFF00") 14 | 15 | XCTAssertEqual(white, UIColor(red: 1, green: 1, blue: 1, alpha: 1.0)) 16 | XCTAssertEqual(black, UIColor(red: 0, green: 0, blue: 0, alpha: 1.0)) 17 | XCTAssertEqual(red, UIColor(red: 1, green: 0, blue: 0, alpha: 1.0)) 18 | XCTAssertEqual(blue, UIColor(red: 0, green: 0, blue: 1, alpha: 1.0)) 19 | XCTAssertEqual(green, UIColor(red: 0, green: 1, blue: 0, alpha: 1.0)) 20 | XCTAssertEqual(yellow, UIColor(red: 1, green: 1, blue: 0, alpha: 1.0)) 21 | } 22 | 23 | func testToHexWithPrefix() { 24 | let white = UIColor.white 25 | let black = UIColor.black 26 | let red = UIColor.red 27 | let blue = UIColor.blue 28 | let green = UIColor.green 29 | let yellow = UIColor.yellow 30 | 31 | XCTAssertEqual(white.hex(), "#FFFFFF") 32 | XCTAssertEqual(black.hex(), "#000000") 33 | XCTAssertEqual(red.hex(), "#FF0000") 34 | XCTAssertEqual(blue.hex(), "#0000FF") 35 | XCTAssertEqual(green.hex(), "#00FF00") 36 | XCTAssertEqual(yellow.hex(), "#FFFF00") 37 | } 38 | 39 | func testToHexWithoutPrefix() { 40 | let white = UIColor.white 41 | let black = UIColor.black 42 | let red = UIColor.red 43 | let blue = UIColor.blue 44 | let green = UIColor.green 45 | let yellow = UIColor.yellow 46 | 47 | XCTAssertEqual(white.hex(hashPrefix: false), "FFFFFF") 48 | XCTAssertEqual(black.hex(hashPrefix: false), "000000") 49 | XCTAssertEqual(red.hex(hashPrefix: false), "FF0000") 50 | XCTAssertEqual(blue.hex(hashPrefix: false), "0000FF") 51 | XCTAssertEqual(green.hex(hashPrefix: false), "00FF00") 52 | XCTAssertEqual(yellow.hex(hashPrefix: false), "FFFF00") 53 | } 54 | 55 | func testAlpha() { 56 | let yellowWithAlpha = UIColor(hex: "#FFFF00").alpha(0.5) 57 | 58 | XCTAssertEqual(yellowWithAlpha, UIColor(red: 1, green: 1, blue: 0, alpha: 1.0).withAlphaComponent(0.5)) 59 | } 60 | 61 | func testGradient() { 62 | let testGradient = [UIColor.black, UIColor.orange].gradient() 63 | 64 | XCTAssertTrue(testGradient as Any is CAGradientLayer) 65 | XCTAssertEqual(testGradient.colors?.count, 2) 66 | XCTAssertEqual( 67 | (testGradient.colors as! [CGColor])[0].colorSpace!.model, 68 | UIColor.black.cgColor.colorSpace!.model) 69 | XCTAssertEqual( 70 | (testGradient.colors as! [CGColor])[1].colorSpace!.model, 71 | UIColor.orange.cgColor.colorSpace!.model) 72 | 73 | let testGradientWithLocation = [UIColor.blue, UIColor.yellow].gradient { gradient in 74 | gradient.locations = [0.25, 1.0] 75 | return gradient 76 | } 77 | 78 | XCTAssertTrue(testGradient as Any is CAGradientLayer) 79 | XCTAssertEqual(testGradient.colors?.count, 2) 80 | XCTAssertEqual( 81 | (testGradientWithLocation.colors as! [CGColor])[0].colorSpace!.model, 82 | UIColor.blue.cgColor.colorSpace!.model) 83 | XCTAssertEqual( 84 | (testGradientWithLocation.colors as! [CGColor])[1].colorSpace!.model, 85 | UIColor.yellow.cgColor.colorSpace!.model) 86 | XCTAssertEqual(testGradientWithLocation.locations!, [0.25,1.0]) 87 | } 88 | 89 | func testComponents() { 90 | let blue = UIColor.blue 91 | let green = UIColor.green 92 | let red = UIColor.red 93 | let black = UIColor.black 94 | let white = UIColor.white 95 | 96 | XCTAssertEqual(blue.redComponent, 0.0) 97 | XCTAssertEqual(blue.greenComponent, 0.0) 98 | XCTAssertEqual(blue.blueComponent, 1.0) 99 | XCTAssertEqual(blue.alphaComponent, 1.0) 100 | 101 | XCTAssertEqual(red.redComponent, 1.0) 102 | XCTAssertEqual(red.greenComponent, 0.0) 103 | XCTAssertEqual(red.blueComponent, 0.0) 104 | XCTAssertEqual(red.alphaComponent, 1.0) 105 | 106 | XCTAssertEqual(green.redComponent, 0.0) 107 | XCTAssertEqual(green.greenComponent, 1.0) 108 | XCTAssertEqual(green.blueComponent, 0.0) 109 | XCTAssertEqual(green.alphaComponent, 1.0) 110 | 111 | XCTAssertEqual(black.redComponent, 0.0) 112 | XCTAssertEqual(black.greenComponent, 0.0) 113 | XCTAssertEqual(black.blueComponent, 0.0) 114 | XCTAssertEqual(black.alphaComponent, 1.0) 115 | 116 | XCTAssertEqual(white.redComponent, 1.0) 117 | XCTAssertEqual(white.greenComponent, 1.0) 118 | XCTAssertEqual(white.blueComponent, 1.0) 119 | XCTAssertEqual(white.alphaComponent, 1.0) 120 | } 121 | 122 | func testBlending() { 123 | let black = UIColor.black 124 | let white = UIColor.white 125 | let yellow = UIColor.yellow 126 | let green = UIColor.green 127 | let red = UIColor.red 128 | let blue = UIColor.blue 129 | let deSaturatedBlue = UIColor(hue: 240.0/360.0, 130 | saturation: 0.1, 131 | brightness: 1.0, 132 | alpha: 1.0) 133 | 134 | let testWhite = black.add(rgba: white) 135 | XCTAssertEqual(testWhite.redComponent, white.redComponent) 136 | XCTAssertEqual(testWhite.greenComponent, white.greenComponent) 137 | XCTAssertEqual(testWhite.blueComponent, white.blueComponent) 138 | 139 | let testYellow = green.add(rgba: red) 140 | XCTAssertEqual(testYellow.redComponent, yellow.redComponent) 141 | XCTAssertEqual(testYellow.greenComponent, yellow.greenComponent) 142 | XCTAssertEqual(testYellow.blueComponent, yellow.blueComponent) 143 | 144 | let testBlue = deSaturatedBlue.add(hue: 0.0, saturation: 1.0, 145 | brightness: 0.0, alpha: 0.0) 146 | XCTAssertEqual(testBlue.redComponent, blue.redComponent) 147 | XCTAssertEqual(testBlue.greenComponent, blue.greenComponent) 148 | XCTAssertEqual(testBlue.blueComponent, blue.blueComponent) 149 | } 150 | 151 | func testIsDark() { 152 | // Colors created in the monochrome colorSpace -> 2 components 153 | let monochromeBlack = UIColor.black 154 | let monochromeWhite = UIColor.white 155 | let monochromeDarkGray = UIColor.darkGray 156 | let monochromeGray = UIColor.gray 157 | let monochromeLightGray = UIColor.lightGray 158 | 159 | // Colors created in the RGBA colorSpace -> 4 components 160 | let black = UIColor(hex: "000") 161 | let white = UIColor(hex: "fff") 162 | let darkGray = UIColor(hex: "555") 163 | let lightGray = UIColor(hex: "aaa") 164 | let yellow = UIColor.yellow 165 | let green = UIColor.green 166 | let red = UIColor.red 167 | let blue = UIColor.blue 168 | 169 | 170 | let isMonochromeBlackDark = monochromeBlack.isDark 171 | XCTAssertEqual(isMonochromeBlackDark, true) 172 | 173 | let isMonochromeWhiteDark = monochromeWhite.isDark 174 | XCTAssertEqual(isMonochromeWhiteDark, false) 175 | 176 | let isMonochromeDarkGrayDark = monochromeDarkGray.isDark 177 | XCTAssertEqual(isMonochromeDarkGrayDark, true) 178 | 179 | let isMonochromeGrayDark = monochromeGray.isDark 180 | XCTAssertEqual(isMonochromeGrayDark, false) 181 | 182 | let isMonochromeLightGrayDark = monochromeLightGray.isDark 183 | XCTAssertEqual(isMonochromeLightGrayDark, false) 184 | 185 | let isBlackDark = black.isDark 186 | XCTAssertEqual(isBlackDark, true) 187 | 188 | let isWhiteDark = white.isDark 189 | XCTAssertEqual(isWhiteDark, false) 190 | 191 | let isDarkGrayDark = darkGray.isDark 192 | XCTAssertEqual(isDarkGrayDark, true) 193 | 194 | let isLightGrayDark = lightGray.isDark 195 | XCTAssertEqual(isLightGrayDark, false) 196 | 197 | let isYellowDark = yellow.isDark 198 | XCTAssertEqual(isYellowDark, false) 199 | 200 | let isGreenDark = green.isDark 201 | XCTAssertEqual(isGreenDark, false) 202 | 203 | let isRedDark = red.isDark 204 | XCTAssertEqual(isRedDark, true) 205 | 206 | let isBlueDark = blue.isDark 207 | XCTAssertEqual(isBlueDark, true) 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Tests/iOS+tvOS/UIImageTests.swift: -------------------------------------------------------------------------------- 1 | @testable import Hue 2 | import UIKit 3 | import XCTest 4 | 5 | class UIImageTests: XCTestCase { 6 | 7 | var image: UIImage! 8 | 9 | override func setUp() { 10 | super.setUp() 11 | let bundle = Bundle(for: self.classForCoder) 12 | let path = bundle.path(forResource: "Random Access Memories", ofType: "png")! 13 | 14 | image = UIImage(contentsOfFile: path)! 15 | } 16 | 17 | func testImageColors() { 18 | let bundle = Bundle(for: self.classForCoder) 19 | let path = bundle.path(forResource: "Random Access Memories", ofType: "png")! 20 | let image = UIImage(contentsOfFile: path)! 21 | 22 | XCTAssertNotNil(image) 23 | 24 | let accuracy: CGFloat = 0.5 25 | let colors = image.colors() 26 | var (red, green, blue): (CGFloat, CGFloat, CGFloat) = (0, 0, 0) 27 | 28 | colors.background.getRed(&red, green: &green, blue: &blue, alpha: nil) 29 | 30 | XCTAssertEqual(red, 0.035, accuracy: accuracy) 31 | XCTAssertEqual(green, 0.05, accuracy: accuracy) 32 | XCTAssertEqual(blue, 0.054, accuracy: accuracy) 33 | 34 | colors.primary.getRed(&red, green: &green, blue: &blue, alpha: nil) 35 | 36 | XCTAssertEqual(red, 0.563, accuracy: accuracy) 37 | XCTAssertEqual(green, 0.572, accuracy: accuracy) 38 | XCTAssertEqual(blue, 0.662, accuracy: accuracy) 39 | 40 | colors.secondary.getRed(&red, green: &green, blue: &blue, alpha: nil) 41 | 42 | XCTAssertEqual(red, 0.746, accuracy: accuracy) 43 | XCTAssertEqual(green, 0.831, accuracy: accuracy) 44 | XCTAssertEqual(blue, 0.878, accuracy: accuracy) 45 | 46 | colors.detail.getRed(&red, green: &green, blue: &blue, alpha: nil) 47 | 48 | XCTAssertEqual(red, 1.000, accuracy: accuracy) 49 | XCTAssertEqual(green, 0.9, accuracy: accuracy) 50 | XCTAssertEqual(blue, 0.7, accuracy: accuracy) 51 | } 52 | 53 | func testPixelColorSubscript() { 54 | XCTAssertNotNil(image) 55 | 56 | let nilExpectation = self.expectation(description: "Expect nil") 57 | let secondExpectation = self.expectation(description: "Expect #090D0E") 58 | let thirdExpectation = self.expectation(description: "Expect #C8DDF0") 59 | 60 | // Expect the color to be `nil` because the y coordinate is outside. 61 | image.color(at: .init(x: 1300, y: -1)) { color in 62 | XCTAssertNil(color) 63 | nilExpectation.fulfill() 64 | } 65 | 66 | // Expect a color to be resolved, more specifically #090D0E 67 | image.color(at: .init(x: 0, y: 0)) { color in 68 | XCTAssertEqual(color?.hex(), "#090D0E") 69 | secondExpectation.fulfill() 70 | } 71 | 72 | // Expect a color to be resolved, more specifically #C8DDF0 73 | image.color(at: .init(x: 535, y: 513)) { color in 74 | XCTAssertEqual(color?.hex(), "#C8DDF0") 75 | thirdExpectation.fulfill() 76 | } 77 | 78 | waitForExpectations(timeout: 10.0, handler: nil) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Tests/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/macOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/macOS/NSColorTests.swift: -------------------------------------------------------------------------------- 1 | @testable import Hue 2 | import AppKit 3 | import XCTest 4 | 5 | class NSColorTests: XCTestCase { 6 | 7 | func testHex() { 8 | let white = NSColor(hex: "#FFFFFF") 9 | let black = NSColor(hex: "000000") 10 | let red = NSColor(hex: "F00") 11 | let blue = NSColor(hex: "#00F") 12 | let green = NSColor(hex: "#00FF00") 13 | let yellow = NSColor(hex: "#FFFF00") 14 | 15 | XCTAssertEqual(white, NSColor(red: 1, green: 1, blue: 1, alpha: 1.0)) 16 | XCTAssertEqual(black, NSColor(red: 0, green: 0, blue: 0, alpha: 1.0)) 17 | XCTAssertEqual(red, NSColor(red: 1, green: 0, blue: 0, alpha: 1.0)) 18 | XCTAssertEqual(blue, NSColor(red: 0, green: 0, blue: 1, alpha: 1.0)) 19 | XCTAssertEqual(green, NSColor(red: 0, green: 1, blue: 0, alpha: 1.0)) 20 | XCTAssertEqual(yellow, NSColor(red: 1, green: 1, blue: 0, alpha: 1.0)) 21 | } 22 | 23 | func testToHexWithPrefix() { 24 | let white = NSColor.white 25 | let black = NSColor.black 26 | let red = NSColor.red 27 | let blue = NSColor.blue 28 | let green = NSColor.green 29 | let yellow = NSColor.yellow 30 | 31 | XCTAssertEqual(white.hex(), "#FFFFFF") 32 | XCTAssertEqual(black.hex(), "#000000") 33 | XCTAssertEqual(red.hex(), "#FF0000") 34 | XCTAssertEqual(blue.hex(), "#0000FF") 35 | XCTAssertEqual(green.hex(), "#00FF00") 36 | XCTAssertEqual(yellow.hex(), "#FFFF00") 37 | } 38 | 39 | func testToHexWithoutPrefix() { 40 | let white = NSColor.white 41 | let black = NSColor.black 42 | let red = NSColor.red 43 | let blue = NSColor.blue 44 | let green = NSColor.green 45 | let yellow = NSColor.yellow 46 | 47 | XCTAssertEqual(white.hex(hashPrefix: false), "FFFFFF") 48 | XCTAssertEqual(black.hex(hashPrefix: false), "000000") 49 | XCTAssertEqual(red.hex(hashPrefix: false), "FF0000") 50 | XCTAssertEqual(blue.hex(hashPrefix: false), "0000FF") 51 | XCTAssertEqual(green.hex(hashPrefix: false), "00FF00") 52 | XCTAssertEqual(yellow.hex(hashPrefix: false), "FFFF00") 53 | } 54 | 55 | func fix_testAlpha() { 56 | let yellowWithAlpha = NSColor(hex: "#FFFF00").alpha(0.5) 57 | 58 | XCTAssertEqual( 59 | yellowWithAlpha, 60 | NSColor(red: 255, green: 255, blue: 0, alpha: 1.0).withAlphaComponent(0.5) 61 | ) 62 | } 63 | 64 | func testGradient() { 65 | let testGradient = [NSColor.black, NSColor.orange].gradient() 66 | 67 | XCTAssertTrue(testGradient.isKind(of: CAGradientLayer.self)) 68 | XCTAssertEqual(testGradient.colors?.count, 2) 69 | XCTAssertEqual( 70 | (testGradient.colors as! [CGColor])[0].colorSpace?.model, 71 | (NSColor.black.cgColor).colorSpace?.model) 72 | XCTAssertEqual( 73 | (testGradient.colors as! [CGColor])[1].colorSpace?.model, 74 | (NSColor.orange.cgColor).colorSpace?.model) 75 | 76 | let testGradientWithLocation = [NSColor.blue, NSColor.yellow].gradient { gradient in 77 | gradient.locations = [0.25, 1.0] 78 | return gradient 79 | } 80 | 81 | XCTAssertTrue(testGradient.isKind(of: CAGradientLayer.self)) 82 | XCTAssertEqual(testGradient.colors?.count, 2) 83 | XCTAssertEqual( 84 | (testGradientWithLocation.colors as! [CGColor])[0].colorSpace?.model, 85 | (NSColor.blue.cgColor).colorSpace?.model) 86 | XCTAssertEqual( 87 | (testGradientWithLocation.colors as! [CGColor])[1].colorSpace?.model, 88 | (NSColor.yellow.cgColor).colorSpace?.model) 89 | XCTAssertEqual(testGradientWithLocation.locations!, [0.25,1.0]) 90 | } 91 | 92 | func testComponents() { 93 | let blue = NSColor.blue 94 | let green = NSColor.green 95 | let red = NSColor.red 96 | let black = NSColor.black 97 | let white = NSColor.white 98 | 99 | XCTAssertEqual(blue.getRed(), 0.0) 100 | XCTAssertEqual(blue.getGreen(), 0.0) 101 | XCTAssertEqual(blue.getBlue(), 1.0) 102 | XCTAssertEqual(blue.getAlpha(), 1.0) 103 | 104 | XCTAssertEqual(red.getRed(), 1.0) 105 | XCTAssertEqual(red.getGreen(), 0.0) 106 | XCTAssertEqual(red.getBlue(), 0.0) 107 | XCTAssertEqual(red.getAlpha(), 1.0) 108 | 109 | XCTAssertEqual(green.getRed(), 0.0) 110 | XCTAssertEqual(green.getGreen(), 1.0) 111 | XCTAssertEqual(green.getBlue(), 0.0) 112 | XCTAssertEqual(green.getAlpha(), 1.0) 113 | 114 | XCTAssertEqual(black.getRed(), 0.0) 115 | XCTAssertEqual(black.getGreen(), 0.0) 116 | XCTAssertEqual(black.getBlue(), 0.0) 117 | XCTAssertEqual(black.getAlpha(), 1.0) 118 | 119 | XCTAssertEqual(white.getRed(), 1.0) 120 | XCTAssertEqual(white.getGreen(), 1.0) 121 | XCTAssertEqual(white.getBlue(), 1.0) 122 | XCTAssertEqual(white.getAlpha(), 1.0) 123 | } 124 | 125 | func testBlending() { 126 | let black = NSColor.black 127 | let white = NSColor.white 128 | let yellow = NSColor.yellow 129 | let green = NSColor.green 130 | let red = NSColor.red 131 | let blue = NSColor.blue 132 | let deSaturatedBlue = NSColor(hue: 240.0/360.0, 133 | saturation: 0.1, 134 | brightness: 1.0, 135 | alpha: 1.0) 136 | 137 | let testWhite = black.add(rgb: white) 138 | XCTAssertEqual(testWhite.getRed(), white.getRed()) 139 | XCTAssertEqual(testWhite.getGreen(), white.getGreen()) 140 | XCTAssertEqual(testWhite.getBlue(), white.getBlue()) 141 | 142 | let testYellow = green.add(rgb: red) 143 | XCTAssertEqual(testYellow.getRed(), yellow.getRed()) 144 | XCTAssertEqual(testYellow.getGreen(), yellow.getGreen()) 145 | XCTAssertEqual(testYellow.getBlue(), yellow.getBlue()) 146 | 147 | let testBlue = deSaturatedBlue.add(hue: 0.0, saturation: 1.0, brightness: 0.0, alpha: 0.0); 148 | XCTAssertEqual(testBlue.getRed(), blue.getRed()) 149 | XCTAssertEqual(testBlue.getGreen(), blue.getGreen()) 150 | XCTAssertEqual(testBlue.getBlue(), blue.getBlue()) 151 | } 152 | 153 | func testIsDark() { 154 | // Colors created in the monochrome colorSpace -> 2 components 155 | let monochromeBlack = NSColor.black 156 | let monochromeWhite = NSColor.white 157 | let monochromeDarkGray = NSColor.darkGray 158 | let monochromeGray = NSColor.gray 159 | let monochromeLightGray = NSColor.lightGray 160 | 161 | // Colors created in the RGBA colorSpace -> 4 components 162 | let black = NSColor(hex: "000") 163 | let white = NSColor(hex: "fff") 164 | let darkGray = NSColor(hex: "555") 165 | let lightGray = NSColor(hex: "aaa") 166 | let yellow = NSColor.yellow 167 | let green = NSColor.green 168 | let red = NSColor.red 169 | let blue = NSColor.blue 170 | 171 | 172 | let isMonochromeBlackDark = monochromeBlack.isDark 173 | XCTAssertEqual(isMonochromeBlackDark, true) 174 | 175 | let isMonochromeWhiteDark = monochromeWhite.isDark 176 | XCTAssertEqual(isMonochromeWhiteDark, false) 177 | 178 | let isMonochromeDarkGrayDark = monochromeDarkGray.isDark 179 | XCTAssertEqual(isMonochromeDarkGrayDark, true) 180 | 181 | let isMonochromeGrayDark = monochromeGray.isDark 182 | XCTAssertEqual(isMonochromeGrayDark, false) 183 | 184 | let isMonochromeLightGrayDark = monochromeLightGray.isDark 185 | XCTAssertEqual(isMonochromeLightGrayDark, false) 186 | 187 | let isBlackDark = black.isDark 188 | XCTAssertEqual(isBlackDark, true) 189 | 190 | let isWhiteDark = white.isDark 191 | XCTAssertEqual(isWhiteDark, false) 192 | 193 | let isDarkGrayDark = darkGray.isDark 194 | XCTAssertEqual(isDarkGrayDark, true) 195 | 196 | // edge case! Should be false, but `rgbComponents()` returns 0.498039215686275 instead of 0.5 for each component 197 | // let isGrayDark = gray.isDark 198 | // XCTAssertEqual(isGrayDark, false) 199 | 200 | let isLightGrayDark = lightGray.isDark 201 | XCTAssertEqual(isLightGrayDark, false) 202 | 203 | let isYellowDark = yellow.isDark 204 | XCTAssertEqual(isYellowDark, false) 205 | 206 | let isGreenDark = green.isDark 207 | XCTAssertEqual(isGreenDark, false) 208 | 209 | let isRedDark = red.isDark 210 | XCTAssertEqual(isRedDark, true) 211 | 212 | let isBlueDark = blue.isDark 213 | XCTAssertEqual(isBlueDark, true) 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /Tests/macOS/NSImageTests.swift: -------------------------------------------------------------------------------- 1 | @testable import Hue 2 | import AppKit 3 | import XCTest 4 | 5 | class NSImageTests: XCTestCase { 6 | 7 | func testImageColors() { 8 | let accuracy: CGFloat = 0.4 9 | let bundle = Bundle(for: self.classForCoder) 10 | let path = bundle.path(forResource: "Random Access Memories", ofType: "png")! 11 | let image = NSImage(contentsOfFile: path)! 12 | 13 | XCTAssertNotNil(image) 14 | 15 | let colors = image.colors() 16 | 17 | var (red, green, blue): (CGFloat, CGFloat, CGFloat) = (0,0,0) 18 | 19 | colors.background.getRed(&red, green: &green, blue: &blue, alpha: nil) 20 | 21 | XCTAssertEqual(red, 0.035, accuracy: accuracy) 22 | XCTAssertEqual(green, 0.05, accuracy: accuracy) 23 | XCTAssertEqual(blue, 0.054, accuracy: accuracy) 24 | 25 | colors.primary.getRed(&red, green: &green, blue: &blue, alpha: nil) 26 | 27 | XCTAssertEqual(red, 0.563, accuracy: accuracy) 28 | XCTAssertEqual(green, 0.572, accuracy: accuracy) 29 | XCTAssertEqual(blue, 0.662, accuracy: accuracy) 30 | 31 | colors.secondary.getRed(&red, green: &green, blue: &blue, alpha: nil) 32 | 33 | XCTAssertEqual(red, 0.746, accuracy: accuracy) 34 | XCTAssertEqual(green, 0.831, accuracy: accuracy) 35 | XCTAssertEqual(blue, 0.878, accuracy: accuracy) 36 | 37 | colors.detail.getRed(&red, green: &green, blue: &blue, alpha: nil) 38 | 39 | XCTAssertEqual(red, 1.000, accuracy: accuracy) 40 | XCTAssertEqual(green, 1.000, accuracy: accuracy) 41 | XCTAssertEqual(blue, 0.85, accuracy: accuracy) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Tests/tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | --------------------------------------------------------------------------------