├── .gitignore ├── Assets └── mononoki-Regular.ttf ├── ColorClockSaver.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── edwardloveall.xcuserdatad │ └── xcschemes │ ├── ColorClockSaver.xcscheme │ └── xcschememanagement.plist ├── ColorClockSaver ├── BackgroundView.swift ├── ColorCodeView.swift ├── ConfigureSheet.swift ├── ConfigureSheet.xib ├── Date.swift ├── Fonts.swift ├── Info.plist ├── LabelView.swift ├── MainView.swift ├── NSColor.swift ├── Settings.swift └── TimeView.swift ├── LICENSE ├── Preview ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── MainMenu.xib └── Info.plist ├── README.md └── Resources ├── screenshot.png ├── thumbnail.png └── thumbnail@2x.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/swift 2 | 3 | ### Swift ### 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xccheckout 26 | *.xcscmblueprint 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # 40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 41 | # Packages/ 42 | # Package.pins 43 | .build/ 44 | 45 | # CocoaPods - Refactored to standalone file 46 | 47 | # Carthage - Refactored to standalone file 48 | 49 | # fastlane 50 | # 51 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 52 | # screenshots whenever they are needed. 53 | # For more information about the recommended setup visit: 54 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 55 | 56 | fastlane/report.xml 57 | fastlane/Preview.html 58 | fastlane/screenshots 59 | fastlane/test_output 60 | 61 | ### Swift.Carthage Stack ### 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build 68 | 69 | ### Swift.CocoaPods Stack ### 70 | ## CocoaPods GitIgnore Template 71 | 72 | # CocoaPods - Only use to conserve bandwidth / Save time on Pushing 73 | # - Also handy if you have a lage number of dependant pods 74 | # - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGONRE THE LOCK FILE 75 | Pods/ 76 | 77 | # End of https://www.gitignore.io/api/swift 78 | -------------------------------------------------------------------------------- /Assets/mononoki-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edwardloveall/ColorClockSaver/22090bd68a8a2bec2fd9278a927c88b16d51ea26/Assets/mononoki-Regular.ttf -------------------------------------------------------------------------------- /ColorClockSaver.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 39300F181F2A80AB0089C010 /* thumbnail.png in Resources */ = {isa = PBXBuildFile; fileRef = 39300F171F2A80A30089C010 /* thumbnail.png */; }; 11 | 39508BE21F213D30006D2C6C /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39508BE11F213D30006D2C6C /* Settings.swift */; }; 12 | 39508BE31F213DA4006D2C6C /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39508BE11F213D30006D2C6C /* Settings.swift */; }; 13 | 399F63A51F2378100057D072 /* ConfigureSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 399F63A41F2378100057D072 /* ConfigureSheet.swift */; }; 14 | 399F63A61F2378230057D072 /* ConfigureSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 399F63A41F2378100057D072 /* ConfigureSheet.swift */; }; 15 | 399F63A81F2378820057D072 /* ConfigureSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 399F63A71F2378820057D072 /* ConfigureSheet.xib */; }; 16 | 399F63A91F237B390057D072 /* ConfigureSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 399F63A71F2378820057D072 /* ConfigureSheet.xib */; }; 17 | 39B2D0291EF591460068BB3F /* mononoki-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 39B2D0281EF591460068BB3F /* mononoki-Regular.ttf */; }; 18 | 39B2D02A1EF591460068BB3F /* mononoki-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 39B2D0281EF591460068BB3F /* mononoki-Regular.ttf */; }; 19 | 39B2D02F1EF59B190068BB3F /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B2D02E1EF59B190068BB3F /* Fonts.swift */; }; 20 | 39B2D0301EF59B190068BB3F /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B2D02E1EF59B190068BB3F /* Fonts.swift */; }; 21 | 39BF177E1EF1BA0600BB834B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BF177D1EF1BA0600BB834B /* MainView.swift */; }; 22 | 39BF179A1EF1C2D400BB834B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BF17991EF1C2D400BB834B /* AppDelegate.swift */; }; 23 | 39BF179E1EF1C2D400BB834B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39BF179D1EF1C2D400BB834B /* Assets.xcassets */; }; 24 | 39BF17A61EF1C2DA00BB834B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BF177D1EF1BA0600BB834B /* MainView.swift */; }; 25 | 39BF17AF1EF1D8B500BB834B /* TimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BF17AE1EF1D8B500BB834B /* TimeView.swift */; }; 26 | 39BF17B01EF1D8B800BB834B /* TimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BF17AE1EF1D8B500BB834B /* TimeView.swift */; }; 27 | 39C18FA0292AA64F00CB529B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 39C18F9E292AA64F00CB529B /* MainMenu.xib */; }; 28 | 39D8923F1EF48C1D0063F53D /* ColorCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D984761EF40F3E006E0617 /* ColorCodeView.swift */; }; 29 | 39D892411EF4BEBD0063F53D /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D892401EF4BEBD0063F53D /* Date.swift */; }; 30 | 39D892421EF4BEBF0063F53D /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D892401EF4BEBD0063F53D /* Date.swift */; }; 31 | 39D984771EF40F3E006E0617 /* ColorCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D984761EF40F3E006E0617 /* ColorCodeView.swift */; }; 32 | 39E88BC41EFD92050014F7EF /* BackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E88BC31EFD92050014F7EF /* BackgroundView.swift */; }; 33 | 39E88BC51EFD92890014F7EF /* BackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E88BC31EFD92050014F7EF /* BackgroundView.swift */; }; 34 | 39E88BC71EFDEC390014F7EF /* NSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E88BC61EFDEC390014F7EF /* NSColor.swift */; }; 35 | 39E88BC81EFDF3060014F7EF /* NSColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E88BC61EFDEC390014F7EF /* NSColor.swift */; }; 36 | 39EA84F11F11A7B1008E1F7E /* LabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39EA84F01F11A7B1008E1F7E /* LabelView.swift */; }; 37 | 39EA84F21F11A94C008E1F7E /* LabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39EA84F01F11A7B1008E1F7E /* LabelView.swift */; }; 38 | /* End PBXBuildFile section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 39300F171F2A80A30089C010 /* thumbnail.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumbnail.png; sourceTree = ""; }; 42 | 39300F1B1F2ACB1D0089C010 /* thumbnail@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumbnail@2x.png"; sourceTree = ""; }; 43 | 39508BE11F213D30006D2C6C /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; 44 | 399F63A41F2378100057D072 /* ConfigureSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigureSheet.swift; sourceTree = ""; }; 45 | 399F63A71F2378820057D072 /* ConfigureSheet.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConfigureSheet.xib; sourceTree = ""; }; 46 | 39B2D0281EF591460068BB3F /* mononoki-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "mononoki-Regular.ttf"; sourceTree = ""; }; 47 | 39B2D02E1EF59B190068BB3F /* Fonts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = ""; }; 48 | 39BF17701EF1B98E00BB834B /* ColorClockSaver.saver */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ColorClockSaver.saver; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 39BF17771EF1B98E00BB834B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 39BF177D1EF1BA0600BB834B /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 51 | 39BF17971EF1C2D400BB834B /* Preview.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Preview.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 39BF17991EF1C2D400BB834B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 53 | 39BF179D1EF1C2D400BB834B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 39BF17A21EF1C2D400BB834B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | 39BF17AE1EF1D8B500BB834B /* TimeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeView.swift; sourceTree = ""; }; 56 | 39C18F9F292AA64F00CB529B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 57 | 39D892401EF4BEBD0063F53D /* Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Date.swift; path = ColorClockSaver/Date.swift; sourceTree = ""; }; 58 | 39D984761EF40F3E006E0617 /* ColorCodeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorCodeView.swift; sourceTree = ""; }; 59 | 39E88BC31EFD92050014F7EF /* BackgroundView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundView.swift; sourceTree = ""; }; 60 | 39E88BC61EFDEC390014F7EF /* NSColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NSColor.swift; path = ColorClockSaver/NSColor.swift; sourceTree = ""; }; 61 | 39EA84F01F11A7B1008E1F7E /* LabelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelView.swift; sourceTree = ""; }; 62 | /* End PBXFileReference section */ 63 | 64 | /* Begin PBXFrameworksBuildPhase section */ 65 | 39BF176C1EF1B98E00BB834B /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | 39BF17941EF1C2D400BB834B /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | /* End PBXFrameworksBuildPhase section */ 80 | 81 | /* Begin PBXGroup section */ 82 | 39300F141F2A7E180089C010 /* Resources */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 39300F171F2A80A30089C010 /* thumbnail.png */, 86 | 39300F1B1F2ACB1D0089C010 /* thumbnail@2x.png */, 87 | ); 88 | path = Resources; 89 | sourceTree = ""; 90 | }; 91 | 3988956C1EF6E32E0006DD3C /* Extensions */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 39D892401EF4BEBD0063F53D /* Date.swift */, 95 | 39E88BC61EFDEC390014F7EF /* NSColor.swift */, 96 | ); 97 | name = Extensions; 98 | sourceTree = ""; 99 | }; 100 | 39B2D0271EF5912C0068BB3F /* Assets */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 39B2D0281EF591460068BB3F /* mononoki-Regular.ttf */, 104 | ); 105 | path = Assets; 106 | sourceTree = ""; 107 | }; 108 | 39BF17661EF1B98E00BB834B = { 109 | isa = PBXGroup; 110 | children = ( 111 | 39BF17721EF1B98E00BB834B /* ColorClockSaver */, 112 | 39BF17981EF1C2D400BB834B /* Preview */, 113 | 39B2D0271EF5912C0068BB3F /* Assets */, 114 | 3988956C1EF6E32E0006DD3C /* Extensions */, 115 | 39300F141F2A7E180089C010 /* Resources */, 116 | 39BF17711EF1B98E00BB834B /* Products */, 117 | ); 118 | sourceTree = ""; 119 | }; 120 | 39BF17711EF1B98E00BB834B /* Products */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 39BF17701EF1B98E00BB834B /* ColorClockSaver.saver */, 124 | 39BF17971EF1C2D400BB834B /* Preview.app */, 125 | ); 126 | name = Products; 127 | sourceTree = ""; 128 | }; 129 | 39BF17721EF1B98E00BB834B /* ColorClockSaver */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 39BF177D1EF1BA0600BB834B /* MainView.swift */, 133 | 39E88BC31EFD92050014F7EF /* BackgroundView.swift */, 134 | 39EA84F01F11A7B1008E1F7E /* LabelView.swift */, 135 | 39BF17AE1EF1D8B500BB834B /* TimeView.swift */, 136 | 39D984761EF40F3E006E0617 /* ColorCodeView.swift */, 137 | 39508BE11F213D30006D2C6C /* Settings.swift */, 138 | 39B2D02E1EF59B190068BB3F /* Fonts.swift */, 139 | 399F63A41F2378100057D072 /* ConfigureSheet.swift */, 140 | 399F63A71F2378820057D072 /* ConfigureSheet.xib */, 141 | 39BF17771EF1B98E00BB834B /* Info.plist */, 142 | ); 143 | path = ColorClockSaver; 144 | sourceTree = ""; 145 | }; 146 | 39BF17981EF1C2D400BB834B /* Preview */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 39C18F9E292AA64F00CB529B /* MainMenu.xib */, 150 | 39BF17991EF1C2D400BB834B /* AppDelegate.swift */, 151 | 39BF179D1EF1C2D400BB834B /* Assets.xcassets */, 152 | 39BF17A21EF1C2D400BB834B /* Info.plist */, 153 | ); 154 | path = Preview; 155 | sourceTree = ""; 156 | }; 157 | /* End PBXGroup section */ 158 | 159 | /* Begin PBXHeadersBuildPhase section */ 160 | 39BF176D1EF1B98E00BB834B /* Headers */ = { 161 | isa = PBXHeadersBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXHeadersBuildPhase section */ 168 | 169 | /* Begin PBXNativeTarget section */ 170 | 39BF176F1EF1B98E00BB834B /* ColorClockSaver */ = { 171 | isa = PBXNativeTarget; 172 | buildConfigurationList = 39BF177A1EF1B98E00BB834B /* Build configuration list for PBXNativeTarget "ColorClockSaver" */; 173 | buildPhases = ( 174 | 39BF176B1EF1B98E00BB834B /* Sources */, 175 | 39BF176C1EF1B98E00BB834B /* Frameworks */, 176 | 39BF176D1EF1B98E00BB834B /* Headers */, 177 | 39BF176E1EF1B98E00BB834B /* Resources */, 178 | ); 179 | buildRules = ( 180 | ); 181 | dependencies = ( 182 | ); 183 | name = ColorClockSaver; 184 | productName = ColorClockSaver; 185 | productReference = 39BF17701EF1B98E00BB834B /* ColorClockSaver.saver */; 186 | productType = "com.apple.product-type.bundle"; 187 | }; 188 | 39BF17961EF1C2D400BB834B /* Preview */ = { 189 | isa = PBXNativeTarget; 190 | buildConfigurationList = 39BF17A51EF1C2D400BB834B /* Build configuration list for PBXNativeTarget "Preview" */; 191 | buildPhases = ( 192 | 39BF17931EF1C2D400BB834B /* Sources */, 193 | 39BF17941EF1C2D400BB834B /* Frameworks */, 194 | 39BF17951EF1C2D400BB834B /* Resources */, 195 | ); 196 | buildRules = ( 197 | ); 198 | dependencies = ( 199 | ); 200 | name = Preview; 201 | productName = Preview; 202 | productReference = 39BF17971EF1C2D400BB834B /* Preview.app */; 203 | productType = "com.apple.product-type.application"; 204 | }; 205 | /* End PBXNativeTarget section */ 206 | 207 | /* Begin PBXProject section */ 208 | 39BF17671EF1B98E00BB834B /* Project object */ = { 209 | isa = PBXProject; 210 | attributes = { 211 | LastSwiftUpdateCheck = 0830; 212 | LastUpgradeCheck = 1410; 213 | ORGANIZATIONNAME = "Edward Loveall"; 214 | TargetAttributes = { 215 | 39BF176F1EF1B98E00BB834B = { 216 | CreatedOnToolsVersion = 8.3.2; 217 | DevelopmentTeam = 365N6VLRMF; 218 | LastSwiftMigration = 0830; 219 | ProvisioningStyle = Automatic; 220 | }; 221 | 39BF17961EF1C2D400BB834B = { 222 | CreatedOnToolsVersion = 8.3.2; 223 | DevelopmentTeam = 365N6VLRMF; 224 | ProvisioningStyle = Automatic; 225 | }; 226 | }; 227 | }; 228 | buildConfigurationList = 39BF176A1EF1B98E00BB834B /* Build configuration list for PBXProject "ColorClockSaver" */; 229 | compatibilityVersion = "Xcode 3.2"; 230 | developmentRegion = en; 231 | hasScannedForEncodings = 0; 232 | knownRegions = ( 233 | en, 234 | Base, 235 | ); 236 | mainGroup = 39BF17661EF1B98E00BB834B; 237 | productRefGroup = 39BF17711EF1B98E00BB834B /* Products */; 238 | projectDirPath = ""; 239 | projectRoot = ""; 240 | targets = ( 241 | 39BF176F1EF1B98E00BB834B /* ColorClockSaver */, 242 | 39BF17961EF1C2D400BB834B /* Preview */, 243 | ); 244 | }; 245 | /* End PBXProject section */ 246 | 247 | /* Begin PBXResourcesBuildPhase section */ 248 | 39BF176E1EF1B98E00BB834B /* Resources */ = { 249 | isa = PBXResourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | 399F63A81F2378820057D072 /* ConfigureSheet.xib in Resources */, 253 | 39B2D0291EF591460068BB3F /* mononoki-Regular.ttf in Resources */, 254 | 39300F181F2A80AB0089C010 /* thumbnail.png in Resources */, 255 | ); 256 | runOnlyForDeploymentPostprocessing = 0; 257 | }; 258 | 39BF17951EF1C2D400BB834B /* Resources */ = { 259 | isa = PBXResourcesBuildPhase; 260 | buildActionMask = 2147483647; 261 | files = ( 262 | 39B2D02A1EF591460068BB3F /* mononoki-Regular.ttf in Resources */, 263 | 39BF179E1EF1C2D400BB834B /* Assets.xcassets in Resources */, 264 | 399F63A91F237B390057D072 /* ConfigureSheet.xib in Resources */, 265 | 39C18FA0292AA64F00CB529B /* MainMenu.xib in Resources */, 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | /* End PBXResourcesBuildPhase section */ 270 | 271 | /* Begin PBXSourcesBuildPhase section */ 272 | 39BF176B1EF1B98E00BB834B /* Sources */ = { 273 | isa = PBXSourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | 39E88BC41EFD92050014F7EF /* BackgroundView.swift in Sources */, 277 | 39D984771EF40F3E006E0617 /* ColorCodeView.swift in Sources */, 278 | 39EA84F11F11A7B1008E1F7E /* LabelView.swift in Sources */, 279 | 39B2D02F1EF59B190068BB3F /* Fonts.swift in Sources */, 280 | 399F63A51F2378100057D072 /* ConfigureSheet.swift in Sources */, 281 | 39D892411EF4BEBD0063F53D /* Date.swift in Sources */, 282 | 39E88BC71EFDEC390014F7EF /* NSColor.swift in Sources */, 283 | 39508BE21F213D30006D2C6C /* Settings.swift in Sources */, 284 | 39BF177E1EF1BA0600BB834B /* MainView.swift in Sources */, 285 | 39BF17AF1EF1D8B500BB834B /* TimeView.swift in Sources */, 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | 39BF17931EF1C2D400BB834B /* Sources */ = { 290 | isa = PBXSourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | 399F63A61F2378230057D072 /* ConfigureSheet.swift in Sources */, 294 | 39E88BC81EFDF3060014F7EF /* NSColor.swift in Sources */, 295 | 39BF17A61EF1C2DA00BB834B /* MainView.swift in Sources */, 296 | 39EA84F21F11A94C008E1F7E /* LabelView.swift in Sources */, 297 | 39D892421EF4BEBF0063F53D /* Date.swift in Sources */, 298 | 39508BE31F213DA4006D2C6C /* Settings.swift in Sources */, 299 | 39BF179A1EF1C2D400BB834B /* AppDelegate.swift in Sources */, 300 | 39E88BC51EFD92890014F7EF /* BackgroundView.swift in Sources */, 301 | 39BF17B01EF1D8B800BB834B /* TimeView.swift in Sources */, 302 | 39B2D0301EF59B190068BB3F /* Fonts.swift in Sources */, 303 | 39D8923F1EF48C1D0063F53D /* ColorCodeView.swift in Sources */, 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | /* End PBXSourcesBuildPhase section */ 308 | 309 | /* Begin PBXVariantGroup section */ 310 | 39C18F9E292AA64F00CB529B /* MainMenu.xib */ = { 311 | isa = PBXVariantGroup; 312 | children = ( 313 | 39C18F9F292AA64F00CB529B /* Base */, 314 | ); 315 | name = MainMenu.xib; 316 | sourceTree = ""; 317 | }; 318 | /* End PBXVariantGroup section */ 319 | 320 | /* Begin XCBuildConfiguration section */ 321 | 39BF17781EF1B98E00BB834B /* Debug */ = { 322 | isa = XCBuildConfiguration; 323 | buildSettings = { 324 | ALWAYS_SEARCH_USER_PATHS = NO; 325 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 326 | CLANG_ANALYZER_NONNULL = YES; 327 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 328 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 329 | CLANG_CXX_LIBRARY = "libc++"; 330 | CLANG_ENABLE_MODULES = YES; 331 | CLANG_ENABLE_OBJC_ARC = YES; 332 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 333 | CLANG_WARN_BOOL_CONVERSION = YES; 334 | CLANG_WARN_COMMA = YES; 335 | CLANG_WARN_CONSTANT_CONVERSION = YES; 336 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 337 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 338 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 339 | CLANG_WARN_EMPTY_BODY = YES; 340 | CLANG_WARN_ENUM_CONVERSION = YES; 341 | CLANG_WARN_INFINITE_RECURSION = YES; 342 | CLANG_WARN_INT_CONVERSION = YES; 343 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 344 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 345 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 346 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 347 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 348 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 349 | CLANG_WARN_STRICT_PROTOTYPES = YES; 350 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 351 | CLANG_WARN_UNREACHABLE_CODE = YES; 352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 353 | CODE_SIGN_IDENTITY = "-"; 354 | COPY_PHASE_STRIP = NO; 355 | DEAD_CODE_STRIPPING = YES; 356 | DEBUG_INFORMATION_FORMAT = dwarf; 357 | ENABLE_STRICT_OBJC_MSGSEND = YES; 358 | ENABLE_TESTABILITY = YES; 359 | GCC_C_LANGUAGE_STANDARD = gnu99; 360 | GCC_DYNAMIC_NO_PIC = NO; 361 | GCC_NO_COMMON_BLOCKS = YES; 362 | GCC_OPTIMIZATION_LEVEL = 0; 363 | GCC_PREPROCESSOR_DEFINITIONS = ( 364 | "DEBUG=1", 365 | "$(inherited)", 366 | ); 367 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 368 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 369 | GCC_WARN_UNDECLARED_SELECTOR = YES; 370 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 371 | GCC_WARN_UNUSED_FUNCTION = YES; 372 | GCC_WARN_UNUSED_VARIABLE = YES; 373 | MACOSX_DEPLOYMENT_TARGET = 10.12; 374 | MTL_ENABLE_DEBUG_INFO = YES; 375 | ONLY_ACTIVE_ARCH = YES; 376 | SDKROOT = macosx; 377 | }; 378 | name = Debug; 379 | }; 380 | 39BF17791EF1B98E00BB834B /* Release */ = { 381 | isa = XCBuildConfiguration; 382 | buildSettings = { 383 | ALWAYS_SEARCH_USER_PATHS = NO; 384 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 385 | CLANG_ANALYZER_NONNULL = YES; 386 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 387 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 388 | CLANG_CXX_LIBRARY = "libc++"; 389 | CLANG_ENABLE_MODULES = YES; 390 | CLANG_ENABLE_OBJC_ARC = YES; 391 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 392 | CLANG_WARN_BOOL_CONVERSION = YES; 393 | CLANG_WARN_COMMA = YES; 394 | CLANG_WARN_CONSTANT_CONVERSION = YES; 395 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 396 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 397 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 398 | CLANG_WARN_EMPTY_BODY = YES; 399 | CLANG_WARN_ENUM_CONVERSION = YES; 400 | CLANG_WARN_INFINITE_RECURSION = YES; 401 | CLANG_WARN_INT_CONVERSION = YES; 402 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 403 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 404 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 405 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 406 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 407 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 408 | CLANG_WARN_STRICT_PROTOTYPES = YES; 409 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 410 | CLANG_WARN_UNREACHABLE_CODE = YES; 411 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 412 | CODE_SIGN_IDENTITY = "-"; 413 | COPY_PHASE_STRIP = NO; 414 | DEAD_CODE_STRIPPING = YES; 415 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 416 | ENABLE_NS_ASSERTIONS = NO; 417 | ENABLE_STRICT_OBJC_MSGSEND = YES; 418 | GCC_C_LANGUAGE_STANDARD = gnu99; 419 | GCC_NO_COMMON_BLOCKS = YES; 420 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 421 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 422 | GCC_WARN_UNDECLARED_SELECTOR = YES; 423 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 424 | GCC_WARN_UNUSED_FUNCTION = YES; 425 | GCC_WARN_UNUSED_VARIABLE = YES; 426 | MACOSX_DEPLOYMENT_TARGET = 10.12; 427 | MTL_ENABLE_DEBUG_INFO = NO; 428 | SDKROOT = macosx; 429 | SWIFT_COMPILATION_MODE = wholemodule; 430 | }; 431 | name = Release; 432 | }; 433 | 39BF177B1EF1B98E00BB834B /* Debug */ = { 434 | isa = XCBuildConfiguration; 435 | buildSettings = { 436 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 437 | CLANG_ENABLE_MODULES = YES; 438 | COMBINE_HIDPI_IMAGES = YES; 439 | CURRENT_PROJECT_VERSION = 1.1; 440 | DEAD_CODE_STRIPPING = YES; 441 | DEVELOPMENT_TEAM = 365N6VLRMF; 442 | INFOPLIST_FILE = ColorClockSaver/Info.plist; 443 | INSTALL_PATH = "$(HOME)/Library/Screen Savers"; 444 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 445 | MACOSX_DEPLOYMENT_TARGET = 10.15; 446 | MARKETING_VERSION = 1.1; 447 | PRODUCT_BUNDLE_IDENTIFIER = com.edwardloveall.ColorClockSaver; 448 | PRODUCT_NAME = "$(TARGET_NAME)"; 449 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 450 | SWIFT_VERSION = 5.0; 451 | WRAPPER_EXTENSION = saver; 452 | }; 453 | name = Debug; 454 | }; 455 | 39BF177C1EF1B98E00BB834B /* Release */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 459 | CLANG_ENABLE_MODULES = YES; 460 | COMBINE_HIDPI_IMAGES = YES; 461 | CURRENT_PROJECT_VERSION = 1.1; 462 | DEAD_CODE_STRIPPING = YES; 463 | DEVELOPMENT_TEAM = 365N6VLRMF; 464 | INFOPLIST_FILE = ColorClockSaver/Info.plist; 465 | INSTALL_PATH = "$(HOME)/Library/Screen Savers"; 466 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 467 | MACOSX_DEPLOYMENT_TARGET = 10.15; 468 | MARKETING_VERSION = 1.1; 469 | PRODUCT_BUNDLE_IDENTIFIER = com.edwardloveall.ColorClockSaver; 470 | PRODUCT_NAME = "$(TARGET_NAME)"; 471 | SWIFT_VERSION = 5.0; 472 | WRAPPER_EXTENSION = saver; 473 | }; 474 | name = Release; 475 | }; 476 | 39BF17A31EF1C2D400BB834B /* Debug */ = { 477 | isa = XCBuildConfiguration; 478 | buildSettings = { 479 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 480 | CODE_SIGN_IDENTITY = "-"; 481 | COMBINE_HIDPI_IMAGES = YES; 482 | DEAD_CODE_STRIPPING = YES; 483 | DEVELOPMENT_TEAM = 365N6VLRMF; 484 | INFOPLIST_FILE = Preview/Info.plist; 485 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 486 | MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; 487 | PRODUCT_BUNDLE_IDENTIFIER = com.edwardloveall.Preview; 488 | PRODUCT_NAME = "$(TARGET_NAME)"; 489 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 490 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 491 | SWIFT_VERSION = 5.0; 492 | }; 493 | name = Debug; 494 | }; 495 | 39BF17A41EF1C2D400BB834B /* Release */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 499 | CODE_SIGN_IDENTITY = "-"; 500 | COMBINE_HIDPI_IMAGES = YES; 501 | DEAD_CODE_STRIPPING = YES; 502 | DEVELOPMENT_TEAM = 365N6VLRMF; 503 | INFOPLIST_FILE = Preview/Info.plist; 504 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 505 | MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; 506 | PRODUCT_BUNDLE_IDENTIFIER = com.edwardloveall.Preview; 507 | PRODUCT_NAME = "$(TARGET_NAME)"; 508 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 509 | SWIFT_VERSION = 5.0; 510 | }; 511 | name = Release; 512 | }; 513 | /* End XCBuildConfiguration section */ 514 | 515 | /* Begin XCConfigurationList section */ 516 | 39BF176A1EF1B98E00BB834B /* Build configuration list for PBXProject "ColorClockSaver" */ = { 517 | isa = XCConfigurationList; 518 | buildConfigurations = ( 519 | 39BF17781EF1B98E00BB834B /* Debug */, 520 | 39BF17791EF1B98E00BB834B /* Release */, 521 | ); 522 | defaultConfigurationIsVisible = 0; 523 | defaultConfigurationName = Release; 524 | }; 525 | 39BF177A1EF1B98E00BB834B /* Build configuration list for PBXNativeTarget "ColorClockSaver" */ = { 526 | isa = XCConfigurationList; 527 | buildConfigurations = ( 528 | 39BF177B1EF1B98E00BB834B /* Debug */, 529 | 39BF177C1EF1B98E00BB834B /* Release */, 530 | ); 531 | defaultConfigurationIsVisible = 0; 532 | defaultConfigurationName = Release; 533 | }; 534 | 39BF17A51EF1C2D400BB834B /* Build configuration list for PBXNativeTarget "Preview" */ = { 535 | isa = XCConfigurationList; 536 | buildConfigurations = ( 537 | 39BF17A31EF1C2D400BB834B /* Debug */, 538 | 39BF17A41EF1C2D400BB834B /* Release */, 539 | ); 540 | defaultConfigurationIsVisible = 0; 541 | defaultConfigurationName = Release; 542 | }; 543 | /* End XCConfigurationList section */ 544 | }; 545 | rootObject = 39BF17671EF1B98E00BB834B /* Project object */; 546 | } 547 | -------------------------------------------------------------------------------- /ColorClockSaver.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ColorClockSaver.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ColorClockSaver.xcodeproj/xcuserdata/edwardloveall.xcuserdatad/xcschemes/ColorClockSaver.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /ColorClockSaver.xcodeproj/xcuserdata/edwardloveall.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ColorClockSaver.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | Preview.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 39BF176F1EF1B98E00BB834B 21 | 22 | primary 23 | 24 | 25 | 39BF17961EF1C2D400BB834B 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ColorClockSaver/BackgroundView.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | class BackgroundView: NSView { 4 | override init(frame frameRect: NSRect) { 5 | super.init(frame: frameRect) 6 | setup() 7 | } 8 | 9 | required init?(coder: NSCoder) { 10 | super.init(coder: coder) 11 | setup() 12 | } 13 | 14 | func setup() { 15 | wantsLayer = true 16 | if let layer = layer { 17 | let date = Date() 18 | layer.backgroundColor = date.asColor().cgColor 19 | } 20 | } 21 | 22 | func update() { 23 | let date = Date() 24 | let newColor = date.asColor().cgColor 25 | if let layer = layer { 26 | let fade = CATransition() 27 | fade.duration = 0.3 28 | layer.add(fade, forKey: "transition") 29 | layer.backgroundColor = newColor 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ColorClockSaver/ColorCodeView.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | class ColorCodeView: LabelView { 4 | override func setup() { 5 | drawsBackground = false 6 | isBezeled = false 7 | isBordered = false 8 | isEditable = false 9 | font = NSFont(name: Fonts.colorCodeFont, size: 0) 10 | backgroundWasLight = Date().asColor().isLight 11 | textColor = Date().asColor().appropriateBlackOrWhite() 12 | } 13 | 14 | func update() { 15 | let date = Date() 16 | let dateColor = date.asColor() 17 | stringValue = date.asHexColorString() 18 | 19 | if dateColor.isLight != backgroundWasLight { 20 | let blackOrWhite = dateColor.appropriateBlackOrWhite() 21 | fade(to: blackOrWhite.withAlphaComponent(preventBurnInAlpha)) 22 | } 23 | backgroundWasLight = dateColor.isLight 24 | } 25 | 26 | func resizeFont(for size: NSSize) { 27 | let newFontSize = size.width * 0.0212 28 | font = NSFont(name: Fonts.colorCodeFont, size: newFontSize) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ColorClockSaver/ConfigureSheet.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | class ConfigureSheet { 4 | static var sharedInstance = ConfigureSheet() 5 | 6 | @IBOutlet var window: NSWindow! 7 | @IBOutlet weak var twelveHourCheck: NSButton! 8 | let settings = Settings() 9 | 10 | init() { 11 | let bundle = Bundle(for: ConfigureSheet.self) 12 | bundle.loadNibNamed("ConfigureSheet", owner: self, topLevelObjects: nil) 13 | twelveHourCheck.state = settings.twelveHourStateForCheckBox() 14 | } 15 | 16 | @IBAction func done(_ sender: NSButton) { 17 | guard let parent = window.sheetParent else { 18 | fatalError("Can't get configure sheet parent window") 19 | } 20 | parent.endSheet(window) 21 | } 22 | 23 | @IBAction func setTwelveHour(_ sender: NSButton) { 24 | let value = sender.state 25 | if value == NSControl.StateValue.on { 26 | settings.isTwelveHour = true 27 | } else { 28 | settings.isTwelveHour = false 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ColorClockSaver/ConfigureSheet.xib: -------------------------------------------------------------------------------- 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 | 39 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /ColorClockSaver/Date.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | extension Date { 4 | private func asRGBComonents() -> (red: Double, green: Double, blue: Double) { 5 | let calendar = Calendar(identifier: .gregorian) 6 | let hour = calendar.component(.hour, from: self) 7 | let minute = calendar.component(.minute, from: self) 8 | let second = calendar.component(.second, from: self) 9 | 10 | let hexHour = (1.0/23) * Double(hour) 11 | let hexMinute = (1.0/59) * Double(minute) 12 | let hexSecond = (1.0/59) * Double(second) 13 | 14 | return ( 15 | red: hexHour, 16 | green: hexMinute, 17 | blue: hexSecond 18 | ) 19 | } 20 | 21 | func asHexColorString() -> String { 22 | let rgbValues = asRGBComonents() 23 | let scaledRed = Int(rgbValues.red * 255) 24 | let scaledGreen = Int(rgbValues.green * 255) 25 | let scaledBlue = Int(rgbValues.blue * 255) 26 | 27 | let hexRed = String(format: "%02x", scaledRed) 28 | let hexGreen = String(format: "%02x", scaledGreen) 29 | let hexBlue = String(format: "%02x", scaledBlue) 30 | 31 | return "\(hexRed)\(hexGreen)\(hexBlue)".uppercased() 32 | } 33 | 34 | func asColor() -> NSColor { 35 | let components = asRGBComonents() 36 | let color = NSColor( 37 | calibratedRed: CGFloat(components.red), 38 | green: CGFloat(components.green), 39 | blue: CGFloat(components.blue), 40 | alpha: 1 41 | ) 42 | 43 | return color 44 | } 45 | 46 | func asDarkenedColor() -> NSColor { 47 | let startColor = asColor() 48 | guard let endColor = startColor.blended(withFraction: 0.12, of: .black) 49 | else { fatalError("could not crate darker gradient color") } 50 | 51 | return endColor 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ColorClockSaver/Fonts.swift: -------------------------------------------------------------------------------- 1 | import AppKit 2 | 3 | class Fonts { 4 | static let timeFont = "mononoki-Regular" 5 | static let colorCodeFont = "mononoki-Regular" 6 | 7 | static func load(fontName name: String, extension suffix: String) { 8 | let bundle = Bundle(for: self) 9 | guard 10 | let url = bundle.url(forResource: name, withExtension: suffix) 11 | else { 12 | fatalError("Could not load font: \(name).\(suffix)") 13 | } 14 | 15 | var error: Unmanaged? = nil 16 | CTFontManagerRegisterFontsForURL(url as CFURL, .process, &error) 17 | if error != nil { 18 | NSLog(String(describing: error)) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ColorClockSaver/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 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2017 Edward Loveall. All rights reserved. 23 | NSPrincipalClass 24 | ColorClockSaver.MainView 25 | 26 | 27 | -------------------------------------------------------------------------------- /ColorClockSaver/LabelView.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | class LabelView: NSTextField { 4 | let preventBurnInAlpha: CGFloat = 0.9 5 | 6 | var frameCount: CGFloat = 1 7 | var startColor = NSColor.black 8 | var endColor = NSColor.black 9 | var backgroundWasLight = false 10 | 11 | override init(frame frameRect: NSRect) { 12 | super.init(frame: frameRect) 13 | setup() 14 | } 15 | 16 | required init?(coder: NSCoder) { 17 | super.init(coder: coder) 18 | setup() 19 | } 20 | 21 | func setup() {} 22 | 23 | func fade(to toColor: NSColor) { 24 | guard let textColor = textColor else { return } 25 | frameCount = 1 26 | startColor = textColor 27 | endColor = toColor 28 | 29 | Timer.scheduledTimer(withTimeInterval: 1/60, repeats: true, block: step) 30 | } 31 | 32 | func step(_ timer: Timer) { 33 | let fraction: CGFloat = frameCount / CGFloat(20) 34 | 35 | if fraction >= 1 { 36 | timer.invalidate() 37 | return 38 | } 39 | 40 | textColor = startColor.blended(withFraction: fraction, of: endColor) 41 | frameCount += 1 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ColorClockSaver/MainView.swift: -------------------------------------------------------------------------------- 1 | import ScreenSaver 2 | 3 | class MainView: ScreenSaverView { 4 | let backgroundView = BackgroundView() 5 | let wrapperView = NSStackView() 6 | let timeView = TimeView() 7 | let colorCodeView = ColorCodeView() 8 | 9 | override func viewDidMoveToWindow() { 10 | wantsLayer = true 11 | animationTimeInterval = 1 12 | 13 | Settings().register() 14 | loadFonts() 15 | configureViews() 16 | layoutViews() 17 | 18 | animateOneFrame() 19 | } 20 | 21 | func loadFonts() { 22 | Fonts.load(fontName: Fonts.timeFont, extension: "ttf") 23 | } 24 | 25 | func configureViews() { 26 | wrapperView.alignment = .centerX 27 | wrapperView.orientation = .vertical 28 | wrapperView.distribution = .equalCentering 29 | wrapperView.addArrangedSubview(timeView) 30 | wrapperView.addArrangedSubview(colorCodeView) 31 | addSubview(backgroundView) 32 | addSubview(wrapperView) 33 | } 34 | 35 | func layoutViews() { 36 | backgroundView.translatesAutoresizingMaskIntoConstraints = false 37 | wrapperView.translatesAutoresizingMaskIntoConstraints = false 38 | 39 | backgroundView.topAnchor.constraint(equalTo: topAnchor).isActive = true 40 | backgroundView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true 41 | backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true 42 | backgroundView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true 43 | 44 | wrapperView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true 45 | wrapperView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true 46 | wrapperView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true 47 | 48 | timeView.resizeFont(for: bounds.size) 49 | colorCodeView.resizeFont(for: bounds.size) 50 | } 51 | 52 | override func draw(_ rect: NSRect) {} 53 | 54 | override func animateOneFrame() { 55 | backgroundView.update() 56 | timeView.update() 57 | colorCodeView.update() 58 | setNeedsDisplay(bounds) 59 | } 60 | 61 | override var hasConfigureSheet: Bool { 62 | return true 63 | } 64 | 65 | override var configureSheet: NSWindow? { 66 | let configureSheet = ConfigureSheet.sharedInstance 67 | return configureSheet.window 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ColorClockSaver/NSColor.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | extension NSColor { 4 | var luma: Float { 5 | let red = 0.2126 * Float(redComponent) 6 | let green = 0.7152 * Float(greenComponent) 7 | let blue = 0.0722 * Float(blueComponent) 8 | 9 | return red + blue + green 10 | } 11 | 12 | var isLight: Bool { 13 | return luma >= 0.6 14 | } 15 | 16 | func appropriateBlackOrWhite() -> NSColor { 17 | if isLight { 18 | return .black 19 | } else { 20 | return .white 21 | } 22 | } 23 | 24 | func rgbaComponents() -> [CGFloat] { 25 | var rgba: [CGFloat] = [0, 0, 0, 0] 26 | getComponents(&rgba) 27 | return rgba 28 | } 29 | 30 | func isColorEqual(_ other: NSColor) -> Bool { 31 | guard 32 | let converted = self.usingColorSpace(.sRGB), 33 | let otherConverted = other.usingColorSpace(.sRGB) 34 | else { 35 | return false 36 | } 37 | 38 | return converted.rgbaComponents() == otherConverted.rgbaComponents() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ColorClockSaver/Settings.swift: -------------------------------------------------------------------------------- 1 | import ScreenSaver 2 | 3 | class Settings { 4 | let defaults = Settings.screenSaverDefaults() 5 | var isTwelveHour: Bool { 6 | get { 7 | return defaults.bool(forKey: "isTwelveHour") 8 | } 9 | set(value) { 10 | defaults.set(value, forKey: "isTwelveHour") 11 | defaults.synchronize() 12 | } 13 | } 14 | 15 | func register() { 16 | let values: [String: Any] = [ 17 | "isTwelveHour": false 18 | ] 19 | defaults.register(defaults: values) 20 | } 21 | 22 | func dateFormat() -> String { 23 | if defaults.bool(forKey: "isTwelveHour") { 24 | return "h:mm:ss" 25 | } else { 26 | return "HH:mm:ss" 27 | } 28 | } 29 | 30 | func twelveHourStateForCheckBox() -> NSControl.StateValue { 31 | if isTwelveHour { 32 | return NSControl.StateValue.on 33 | } else { 34 | return NSControl.StateValue.off 35 | } 36 | } 37 | 38 | private static func screenSaverDefaults() -> ScreenSaverDefaults { 39 | guard let bundleId = Bundle(for: Settings.self).bundleIdentifier else { 40 | fatalError("Could not find a bundle identifier") 41 | } 42 | 43 | guard let defaults = ScreenSaverDefaults(forModuleWithName: bundleId) else { 44 | fatalError("Could not create ScreenSaverDefaults instance") 45 | } 46 | 47 | return defaults 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ColorClockSaver/TimeView.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | class TimeView: LabelView { 4 | let settings = Settings() 5 | 6 | override func setup() { 7 | drawsBackground = false 8 | isBezeled = false 9 | isBordered = false 10 | isEditable = false 11 | font = NSFont(name: Fonts.timeFont, size: 0) 12 | backgroundWasLight = Date().asColor().isLight 13 | textColor = Date().asColor().appropriateBlackOrWhite() 14 | } 15 | 16 | func update() { 17 | let date = Date() 18 | let dateColor = date.asColor() 19 | let formatter = DateFormatter() 20 | formatter.dateFormat = settings.dateFormat() 21 | let dateString = formatter.string(from: date) 22 | stringValue = dateString 23 | 24 | if dateColor.isLight != backgroundWasLight { 25 | let blackOrWhite = dateColor.appropriateBlackOrWhite() 26 | fade(to: blackOrWhite.withAlphaComponent(preventBurnInAlpha)) 27 | } 28 | backgroundWasLight = dateColor.isLight 29 | } 30 | 31 | func resizeFont(for size: NSSize) { 32 | let newFontSize = size.width * 0.1 33 | font = NSFont(name: Fonts.timeFont, size: newFontSize) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Edward Loveall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | 24 | 25 | ============================== 26 | mononoki font License 27 | ============================== 28 | 29 | Copyright (c) 2013, Matthias Tellen matthias.tellen@googlemail.com, 30 | with Reserved Font Name monoOne. 31 | 32 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 33 | This license is copied below, and is also available with a FAQ at: 34 | http://scripts.sil.org/OFL 35 | 36 | 37 | ----------------------------------------------------------- 38 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 39 | ----------------------------------------------------------- 40 | 41 | PREAMBLE 42 | The goals of the Open Font License (OFL) are to stimulate worldwide 43 | development of collaborative font projects, to support the font creation 44 | efforts of academic and linguistic communities, and to provide a free and 45 | open framework in which fonts may be shared and improved in partnership 46 | with others. 47 | 48 | The OFL allows the licensed fonts to be used, studied, modified and 49 | redistributed freely as long as they are not sold by themselves. The 50 | fonts, including any derivative works, can be bundled, embedded, 51 | redistributed and/or sold with any software provided that any reserved 52 | names are not used by derivative works. The fonts and derivatives, 53 | however, cannot be released under any other type of license. The 54 | requirement for fonts to remain under this license does not apply 55 | to any document created using the fonts or their derivatives. 56 | 57 | DEFINITIONS 58 | "Font Software" refers to the set of files released by the Copyright 59 | Holder(s) under this license and clearly marked as such. This may 60 | include source files, build scripts and documentation. 61 | 62 | "Reserved Font Name" refers to any names specified as such after the 63 | copyright statement(s). 64 | 65 | "Original Version" refers to the collection of Font Software components as 66 | distributed by the Copyright Holder(s). 67 | 68 | "Modified Version" refers to any derivative made by adding to, deleting, 69 | or substituting -- in part or in whole -- any of the components of the 70 | Original Version, by changing formats or by porting the Font Software to a 71 | new environment. 72 | 73 | "Author" refers to any designer, engineer, programmer, technical 74 | writer or other person who contributed to the Font Software. 75 | 76 | PERMISSION & CONDITIONS 77 | Permission is hereby granted, free of charge, to any person obtaining 78 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 79 | redistribute, and sell modified and unmodified copies of the Font 80 | Software, subject to the following conditions: 81 | 82 | 1) Neither the Font Software nor any of its individual components, 83 | in Original or Modified Versions, may be sold by itself. 84 | 85 | 2) Original or Modified Versions of the Font Software may be bundled, 86 | redistributed and/or sold with any software, provided that each copy 87 | contains the above copyright notice and this license. These can be 88 | included either as stand-alone text files, human-readable headers or 89 | in the appropriate machine-readable metadata fields within text or 90 | binary files as long as those fields can be easily viewed by the user. 91 | 92 | 3) No Modified Version of the Font Software may use the Reserved Font 93 | Name(s) unless explicit written permission is granted by the corresponding 94 | Copyright Holder. This restriction only applies to the primary font name as 95 | presented to the users. 96 | 97 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 98 | Software shall not be used to promote, endorse or advertise any 99 | Modified Version, except to acknowledge the contribution(s) of the 100 | Copyright Holder(s) and the Author(s) or with their explicit written 101 | permission. 102 | 103 | 5) The Font Software, modified or unmodified, in part or in whole, 104 | must be distributed entirely under this license, and must not be 105 | distributed under any other license. The requirement for fonts to 106 | remain under this license does not apply to any document created 107 | using the Font Software. 108 | 109 | TERMINATION 110 | This license becomes null and void if any of the above conditions are 111 | not met. 112 | 113 | DISCLAIMER 114 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 115 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 116 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 117 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 118 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 119 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 120 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 121 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 122 | OTHER DEALINGS IN THE FONT SOFTWARE. 123 | -------------------------------------------------------------------------------- /Preview/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | @NSApplicationMain 4 | class AppDelegate: NSObject, NSApplicationDelegate { 5 | 6 | @IBOutlet var window: NSWindow! 7 | let configureSheet = ConfigureSheet.sharedInstance 8 | 9 | func applicationDidFinishLaunching(_ aNotification: Notification) { 10 | setDefaults() 11 | guard let screenSaverView = window.contentView as? MainView 12 | else { fatalError("could not cast window's contentView as a MainView") } 13 | guard let screen = NSScreen.main 14 | else { fatalError("could not retrive main screen") } 15 | 16 | window.setFrame(screen.frame, display: true) 17 | window.delegate = self 18 | let timer = Timer.scheduledTimer(timeInterval: screenSaverView.animationTimeInterval, 19 | target: screenSaverView, 20 | selector: #selector(screenSaverView.animateOneFrame), 21 | userInfo: nil, 22 | repeats: true) 23 | timer.fire() 24 | 25 | screenSaverView.timeView.resizeFont(for: screenSaverView.bounds.size) 26 | screenSaverView.colorCodeView.resizeFont(for: screenSaverView.bounds.size) 27 | } 28 | 29 | func applicationWillTerminate(_ aNotification: Notification) {} 30 | 31 | @IBAction func openConfigureSheet(sender: NSMenuItem) { 32 | window.beginSheet(configureSheet.window, completionHandler: nil) 33 | } 34 | 35 | func setDefaults() { 36 | let args = CommandLine.arguments 37 | let defaults = Settings() 38 | if let index = args.firstIndex(of: "-isTwelveHour") { 39 | let value = args[index + 1] == "YES" ? true : false 40 | defaults.isTwelveHour = value 41 | } 42 | } 43 | } 44 | 45 | extension AppDelegate: NSWindowDelegate { 46 | func windowDidResize(_ notification: Notification) { 47 | guard let screenSaverView = window.contentView as? MainView 48 | else { fatalError("could not cast window's contentView as a MainView") } 49 | screenSaverView.timeView.resizeFont(for: screenSaverView.bounds.size) 50 | screenSaverView.colorCodeView.resizeFont(for: screenSaverView.bounds.size) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Preview/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Preview/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 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 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | Default 543 | 544 | 545 | 546 | 547 | 548 | 549 | Left to Right 550 | 551 | 552 | 553 | 554 | 555 | 556 | Right to Left 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | Default 568 | 569 | 570 | 571 | 572 | 573 | 574 | Left to Right 575 | 576 | 577 | 578 | 579 | 580 | 581 | Right to Left 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | -------------------------------------------------------------------------------- /Preview/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2017 Edward Loveall. All rights reserved. 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![A screenshot of the ColorClock Screensaver](./Resources/screenshot.png) 2 | 3 | # A ScreenSaver for macOS 4 | 5 | [Announcement blog post](https://blog.edwardloveall.com/colorclocksaver) 6 | 7 | ## Installation 8 | 9 | >Note: This screensaver requires macOS Catalina (10.15) or higher. 10 | 11 | Download the latest [release](https://github.com/edwardloveall/ColorClockSaver/releases/latest) and place it in your `~/Library/Screen Savers/` directory. Then, open System Preferences > Desktop & Screen Saver and select ColorClockSaver from the list. 12 | -------------------------------------------------------------------------------- /Resources/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edwardloveall/ColorClockSaver/22090bd68a8a2bec2fd9278a927c88b16d51ea26/Resources/screenshot.png -------------------------------------------------------------------------------- /Resources/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edwardloveall/ColorClockSaver/22090bd68a8a2bec2fd9278a927c88b16d51ea26/Resources/thumbnail.png -------------------------------------------------------------------------------- /Resources/thumbnail@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edwardloveall/ColorClockSaver/22090bd68a8a2bec2fd9278a927c88b16d51ea26/Resources/thumbnail@2x.png --------------------------------------------------------------------------------