├── .gitignore ├── Images ├── AppIcon100x100.png └── AppWindow.png ├── LICENSE ├── Mac Cache Cleaner.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Mac Cache Cleaner.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── MacCacheCleaner ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── AppIcon_128.png │ │ ├── AppIcon_128@2x.png │ │ ├── AppIcon_16.png │ │ ├── AppIcon_16@2x.png │ │ ├── AppIcon_256.png │ │ ├── AppIcon_256@2x.png │ │ ├── AppIcon_32.png │ │ ├── AppIcon_32@2x.png │ │ ├── AppIcon_512.png │ │ ├── AppIcon_512@2x.png │ │ └── Contents.json │ ├── Contents.json │ └── StatusIcon.imageset │ │ ├── Contents.json │ │ ├── StatusIcon.png │ │ ├── StatusIcon@2x.png │ │ └── StatusIcon@3x.png ├── Constants.swift ├── Extensions │ ├── FileManager+Size.swift │ ├── NSWindowController+intialize.swift │ ├── URL.swift │ └── URLSession+Result.swift ├── Info.plist ├── MacCacheCleaner.entitlements ├── MainViewController.swift ├── Models │ ├── CacheItem.swift │ ├── CacheList.swift │ └── Location.swift ├── Others │ ├── AutoStartSpinner.swift │ ├── CacheFetcher.swift │ ├── Log.swift │ ├── Other.swift │ ├── StoryboardLoadable.swift │ └── Tagged.swift ├── TableViewHandler.swift ├── VersionHandler.swift └── View │ ├── Base.lproj │ └── Main.storyboard │ └── CacheTableCellView.swift ├── MacCacheCleanerTests ├── Info.plist └── JSONTests.swift ├── Podfile ├── Podfile.lock ├── README.md └── Source.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | .DS_Store 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | xcuserdata 14 | *.xccheckout 15 | *.moved-aside 16 | DerivedData 17 | *.hmap 18 | *.ipa 19 | *.xcuserstate 20 | 21 | # CocoaPods 22 | # 23 | # We recommend against adding the Pods directory to your .gitignore. However 24 | # you should judge for yourself, the pros and cons are mentioned at: 25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 26 | # 27 | Pods/ 28 | 29 | # Carthage 30 | # 31 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 32 | # Carthage/Checkouts 33 | 34 | Carthage/Build 35 | -------------------------------------------------------------------------------- /Images/AppIcon100x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/Images/AppIcon100x100.png -------------------------------------------------------------------------------- /Images/AppWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/Images/AppWindow.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kaunteya Suryawanshi 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 | -------------------------------------------------------------------------------- /Mac Cache Cleaner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E309EC7820EE49B200D3D16F /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = E309EC7720EE49B200D3D16F /* Log.swift */; }; 11 | E3197F1020E78B8C00746439 /* URLSession+Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3197F0F20E78B8C00746439 /* URLSession+Result.swift */; }; 12 | E3197F2420E8009500746439 /* Source.json in Resources */ = {isa = PBXBuildFile; fileRef = E3197F1520E8007500746439 /* Source.json */; }; 13 | E3197F2820E8036200746439 /* JSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3197F2720E8036200746439 /* JSONTests.swift */; }; 14 | E3197F2E20E90A6C00746439 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3197F2D20E90A6C00746439 /* MainViewController.swift */; }; 15 | E32B71DC20F11E6300158B7F /* Tagged.swift in Sources */ = {isa = PBXBuildFile; fileRef = E32B71DB20F11E6300158B7F /* Tagged.swift */; }; 16 | E32B71E020F4A2E600158B7F /* TableViewHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E32B71DF20F4A2E600158B7F /* TableViewHandler.swift */; }; 17 | E34E83002079CD5200BA09DF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E34E82FF2079CD5200BA09DF /* AppDelegate.swift */; }; 18 | E34E83042079CD5400BA09DF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E34E83032079CD5400BA09DF /* Assets.xcassets */; }; 19 | E34E83072079CD5400BA09DF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E34E83052079CD5400BA09DF /* Main.storyboard */; }; 20 | E34E83122079D41500BA09DF /* CacheItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E34E83112079D41500BA09DF /* CacheItem.swift */; }; 21 | E352B6B420E90E02004C276B /* CacheTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E352B6B320E90E02004C276B /* CacheTableCellView.swift */; }; 22 | E389A46320EA651B0044B20A /* CacheList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E389A46220EA651B0044B20A /* CacheList.swift */; }; 23 | E389A46520EA98470044B20A /* CacheFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E389A46420EA98470044B20A /* CacheFetcher.swift */; }; 24 | E389A46720EAA0A20044B20A /* NSWindowController+intialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E389A46620EAA0A20044B20A /* NSWindowController+intialize.swift */; }; 25 | E38C8D4C20F8B9BD00239225 /* StoryboardLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38C8D4B20F8B9BD00239225 /* StoryboardLoadable.swift */; }; 26 | E38C8D4E20F8E83000239225 /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38C8D4D20F8E83000239225 /* Location.swift */; }; 27 | E399416D20F7BD49004BD4A4 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = E399416C20F7BD48004BD4A4 /* URL.swift */; }; 28 | E399416F20F7C105004BD4A4 /* VersionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E399416E20F7C105004BD4A4 /* VersionHandler.swift */; }; 29 | E399417120F7C336004BD4A4 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E399417020F7C336004BD4A4 /* Constants.swift */; }; 30 | E3B073B720F75E94009DA160 /* AutoStartSpinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3B073B620F75E94009DA160 /* AutoStartSpinner.swift */; }; 31 | E3F7285820E0FF6F007B0CB0 /* FileManager+Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3F7285720E0FF6F007B0CB0 /* FileManager+Size.swift */; }; 32 | E3F728D920E3B1C1007B0CB0 /* Other.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3F728D820E3B1C1007B0CB0 /* Other.swift */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXContainerItemProxy section */ 36 | E3197F1F20E8008900746439 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = E34E82F42079CD5200BA09DF /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = E34E82FB2079CD5200BA09DF; 41 | remoteInfo = MacCacheCleaner; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | E309EC7720EE49B200D3D16F /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; 47 | E3197F0F20E78B8C00746439 /* URLSession+Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+Result.swift"; sourceTree = ""; }; 48 | E3197F1520E8007500746439 /* Source.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = Source.json; sourceTree = SOURCE_ROOT; }; 49 | E3197F1A20E8008900746439 /* Mac Cache CleanerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Mac Cache CleanerTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | E3197F1E20E8008900746439 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | E3197F2720E8036200746439 /* JSONTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONTests.swift; sourceTree = ""; }; 52 | E3197F2D20E90A6C00746439 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 53 | E32B71DB20F11E6300158B7F /* Tagged.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tagged.swift; sourceTree = ""; }; 54 | E32B71DF20F4A2E600158B7F /* TableViewHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewHandler.swift; sourceTree = ""; }; 55 | E34E82FC2079CD5200BA09DF /* Mac Cache Cleaner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mac Cache Cleaner.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | E34E82FF2079CD5200BA09DF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 57 | E34E83032079CD5400BA09DF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 58 | E34E83062079CD5400BA09DF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 59 | E34E83082079CD5400BA09DF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | E34E83092079CD5400BA09DF /* MacCacheCleaner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MacCacheCleaner.entitlements; sourceTree = ""; }; 61 | E34E83112079D41500BA09DF /* CacheItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheItem.swift; sourceTree = ""; }; 62 | E352B6B320E90E02004C276B /* CacheTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheTableCellView.swift; sourceTree = ""; }; 63 | E389A46220EA651B0044B20A /* CacheList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheList.swift; sourceTree = ""; }; 64 | E389A46420EA98470044B20A /* CacheFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheFetcher.swift; sourceTree = ""; }; 65 | E389A46620EAA0A20044B20A /* NSWindowController+intialize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSWindowController+intialize.swift"; sourceTree = ""; }; 66 | E38C8D4B20F8B9BD00239225 /* StoryboardLoadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryboardLoadable.swift; sourceTree = ""; }; 67 | E38C8D4D20F8E83000239225 /* Location.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = ""; }; 68 | E399416C20F7BD48004BD4A4 /* URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URL.swift; sourceTree = ""; }; 69 | E399416E20F7C105004BD4A4 /* VersionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionHandler.swift; sourceTree = ""; }; 70 | E399417020F7C336004BD4A4 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 71 | E3B073B620F75E94009DA160 /* AutoStartSpinner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoStartSpinner.swift; sourceTree = ""; }; 72 | E3F7285720E0FF6F007B0CB0 /* FileManager+Size.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Size.swift"; sourceTree = ""; }; 73 | E3F728D820E3B1C1007B0CB0 /* Other.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Other.swift; sourceTree = ""; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | E3197F1720E8008900746439 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | E34E82F92079CD5200BA09DF /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | /* End PBXFrameworksBuildPhase section */ 92 | 93 | /* Begin PBXGroup section */ 94 | E3197F1B20E8008900746439 /* MacCacheCleanerTests */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | E3197F2720E8036200746439 /* JSONTests.swift */, 98 | E3197F1E20E8008900746439 /* Info.plist */, 99 | ); 100 | path = MacCacheCleanerTests; 101 | sourceTree = ""; 102 | }; 103 | E32B71C520F083AD00158B7F /* View */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | E34E83052079CD5400BA09DF /* Main.storyboard */, 107 | E352B6B320E90E02004C276B /* CacheTableCellView.swift */, 108 | ); 109 | path = View; 110 | sourceTree = ""; 111 | }; 112 | E34E82F32079CD5200BA09DF = { 113 | isa = PBXGroup; 114 | children = ( 115 | E34E82FE2079CD5200BA09DF /* MacCacheCleaner */, 116 | E3197F1B20E8008900746439 /* MacCacheCleanerTests */, 117 | E34E82FD2079CD5200BA09DF /* Products */, 118 | ); 119 | sourceTree = ""; 120 | }; 121 | E34E82FD2079CD5200BA09DF /* Products */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | E34E82FC2079CD5200BA09DF /* Mac Cache Cleaner.app */, 125 | E3197F1A20E8008900746439 /* Mac Cache CleanerTests.xctest */, 126 | ); 127 | name = Products; 128 | sourceTree = ""; 129 | }; 130 | E34E82FE2079CD5200BA09DF /* MacCacheCleaner */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | E34E82FF2079CD5200BA09DF /* AppDelegate.swift */, 134 | E3197F2D20E90A6C00746439 /* MainViewController.swift */, 135 | E32B71DF20F4A2E600158B7F /* TableViewHandler.swift */, 136 | E399416E20F7C105004BD4A4 /* VersionHandler.swift */, 137 | E399417020F7C336004BD4A4 /* Constants.swift */, 138 | E32B71C520F083AD00158B7F /* View */, 139 | E3F728D620E3B02C007B0CB0 /* Models */, 140 | E3B073B520F75E3D009DA160 /* Others */, 141 | E3F7285D20E10720007B0CB0 /* Extensions */, 142 | E34E83032079CD5400BA09DF /* Assets.xcassets */, 143 | E3197F1520E8007500746439 /* Source.json */, 144 | E34E83082079CD5400BA09DF /* Info.plist */, 145 | E34E83092079CD5400BA09DF /* MacCacheCleaner.entitlements */, 146 | ); 147 | path = MacCacheCleaner; 148 | sourceTree = ""; 149 | }; 150 | E3B073B520F75E3D009DA160 /* Others */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | E309EC7720EE49B200D3D16F /* Log.swift */, 154 | E389A46420EA98470044B20A /* CacheFetcher.swift */, 155 | E3F728D820E3B1C1007B0CB0 /* Other.swift */, 156 | E32B71DB20F11E6300158B7F /* Tagged.swift */, 157 | E3B073B620F75E94009DA160 /* AutoStartSpinner.swift */, 158 | E38C8D4B20F8B9BD00239225 /* StoryboardLoadable.swift */, 159 | ); 160 | path = Others; 161 | sourceTree = ""; 162 | }; 163 | E3F7285D20E10720007B0CB0 /* Extensions */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | E3F7285720E0FF6F007B0CB0 /* FileManager+Size.swift */, 167 | E389A46620EAA0A20044B20A /* NSWindowController+intialize.swift */, 168 | E3197F0F20E78B8C00746439 /* URLSession+Result.swift */, 169 | E399416C20F7BD48004BD4A4 /* URL.swift */, 170 | ); 171 | path = Extensions; 172 | sourceTree = ""; 173 | }; 174 | E3F728D620E3B02C007B0CB0 /* Models */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | E38C8D4D20F8E83000239225 /* Location.swift */, 178 | E34E83112079D41500BA09DF /* CacheItem.swift */, 179 | E389A46220EA651B0044B20A /* CacheList.swift */, 180 | ); 181 | path = Models; 182 | sourceTree = ""; 183 | }; 184 | /* End PBXGroup section */ 185 | 186 | /* Begin PBXNativeTarget section */ 187 | E3197F1920E8008900746439 /* Mac Cache CleanerTests */ = { 188 | isa = PBXNativeTarget; 189 | buildConfigurationList = E3197F2120E8008900746439 /* Build configuration list for PBXNativeTarget "Mac Cache CleanerTests" */; 190 | buildPhases = ( 191 | E3197F1620E8008900746439 /* Sources */, 192 | E3197F1720E8008900746439 /* Frameworks */, 193 | E3197F1820E8008900746439 /* Resources */, 194 | ); 195 | buildRules = ( 196 | ); 197 | dependencies = ( 198 | E3197F2020E8008900746439 /* PBXTargetDependency */, 199 | ); 200 | name = "Mac Cache CleanerTests"; 201 | productName = MacCacheCleanerTests; 202 | productReference = E3197F1A20E8008900746439 /* Mac Cache CleanerTests.xctest */; 203 | productType = "com.apple.product-type.bundle.unit-test"; 204 | }; 205 | E34E82FB2079CD5200BA09DF /* Mac Cache Cleaner */ = { 206 | isa = PBXNativeTarget; 207 | buildConfigurationList = E34E830C2079CD5400BA09DF /* Build configuration list for PBXNativeTarget "Mac Cache Cleaner" */; 208 | buildPhases = ( 209 | E34E82F82079CD5200BA09DF /* Sources */, 210 | E34E82F92079CD5200BA09DF /* Frameworks */, 211 | E34E82FA2079CD5200BA09DF /* Resources */, 212 | ); 213 | buildRules = ( 214 | ); 215 | dependencies = ( 216 | ); 217 | name = "Mac Cache Cleaner"; 218 | productName = MacCacheCleaner; 219 | productReference = E34E82FC2079CD5200BA09DF /* Mac Cache Cleaner.app */; 220 | productType = "com.apple.product-type.application"; 221 | }; 222 | /* End PBXNativeTarget section */ 223 | 224 | /* Begin PBXProject section */ 225 | E34E82F42079CD5200BA09DF /* Project object */ = { 226 | isa = PBXProject; 227 | attributes = { 228 | LastSwiftUpdateCheck = 0940; 229 | LastUpgradeCheck = 0930; 230 | ORGANIZATIONNAME = "Kaunteya Suryawanshi"; 231 | TargetAttributes = { 232 | E3197F1920E8008900746439 = { 233 | CreatedOnToolsVersion = 9.4.1; 234 | LastSwiftMigration = 1030; 235 | TestTargetID = E34E82FB2079CD5200BA09DF; 236 | }; 237 | E34E82FB2079CD5200BA09DF = { 238 | CreatedOnToolsVersion = 9.3; 239 | SystemCapabilities = { 240 | com.apple.Sandbox = { 241 | enabled = 0; 242 | }; 243 | }; 244 | }; 245 | }; 246 | }; 247 | buildConfigurationList = E34E82F72079CD5200BA09DF /* Build configuration list for PBXProject "Mac Cache Cleaner" */; 248 | compatibilityVersion = "Xcode 9.3"; 249 | developmentRegion = en; 250 | hasScannedForEncodings = 0; 251 | knownRegions = ( 252 | en, 253 | Base, 254 | ); 255 | mainGroup = E34E82F32079CD5200BA09DF; 256 | productRefGroup = E34E82FD2079CD5200BA09DF /* Products */; 257 | projectDirPath = ""; 258 | projectRoot = ""; 259 | targets = ( 260 | E34E82FB2079CD5200BA09DF /* Mac Cache Cleaner */, 261 | E3197F1920E8008900746439 /* Mac Cache CleanerTests */, 262 | ); 263 | }; 264 | /* End PBXProject section */ 265 | 266 | /* Begin PBXResourcesBuildPhase section */ 267 | E3197F1820E8008900746439 /* Resources */ = { 268 | isa = PBXResourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | E3197F2420E8009500746439 /* Source.json in Resources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | E34E82FA2079CD5200BA09DF /* Resources */ = { 276 | isa = PBXResourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | E34E83042079CD5400BA09DF /* Assets.xcassets in Resources */, 280 | E34E83072079CD5400BA09DF /* Main.storyboard in Resources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | /* End PBXResourcesBuildPhase section */ 285 | 286 | /* Begin PBXSourcesBuildPhase section */ 287 | E3197F1620E8008900746439 /* Sources */ = { 288 | isa = PBXSourcesBuildPhase; 289 | buildActionMask = 2147483647; 290 | files = ( 291 | E3197F2820E8036200746439 /* JSONTests.swift in Sources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | E34E82F82079CD5200BA09DF /* Sources */ = { 296 | isa = PBXSourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | E34E83122079D41500BA09DF /* CacheItem.swift in Sources */, 300 | E399417120F7C336004BD4A4 /* Constants.swift in Sources */, 301 | E309EC7820EE49B200D3D16F /* Log.swift in Sources */, 302 | E389A46720EAA0A20044B20A /* NSWindowController+intialize.swift in Sources */, 303 | E3F7285820E0FF6F007B0CB0 /* FileManager+Size.swift in Sources */, 304 | E32B71E020F4A2E600158B7F /* TableViewHandler.swift in Sources */, 305 | E38C8D4C20F8B9BD00239225 /* StoryboardLoadable.swift in Sources */, 306 | E3B073B720F75E94009DA160 /* AutoStartSpinner.swift in Sources */, 307 | E32B71DC20F11E6300158B7F /* Tagged.swift in Sources */, 308 | E399416F20F7C105004BD4A4 /* VersionHandler.swift in Sources */, 309 | E3197F2E20E90A6C00746439 /* MainViewController.swift in Sources */, 310 | E34E83002079CD5200BA09DF /* AppDelegate.swift in Sources */, 311 | E399416D20F7BD49004BD4A4 /* URL.swift in Sources */, 312 | E352B6B420E90E02004C276B /* CacheTableCellView.swift in Sources */, 313 | E38C8D4E20F8E83000239225 /* Location.swift in Sources */, 314 | E389A46320EA651B0044B20A /* CacheList.swift in Sources */, 315 | E3197F1020E78B8C00746439 /* URLSession+Result.swift in Sources */, 316 | E389A46520EA98470044B20A /* CacheFetcher.swift in Sources */, 317 | E3F728D920E3B1C1007B0CB0 /* Other.swift in Sources */, 318 | ); 319 | runOnlyForDeploymentPostprocessing = 0; 320 | }; 321 | /* End PBXSourcesBuildPhase section */ 322 | 323 | /* Begin PBXTargetDependency section */ 324 | E3197F2020E8008900746439 /* PBXTargetDependency */ = { 325 | isa = PBXTargetDependency; 326 | target = E34E82FB2079CD5200BA09DF /* Mac Cache Cleaner */; 327 | targetProxy = E3197F1F20E8008900746439 /* PBXContainerItemProxy */; 328 | }; 329 | /* End PBXTargetDependency section */ 330 | 331 | /* Begin PBXVariantGroup section */ 332 | E34E83052079CD5400BA09DF /* Main.storyboard */ = { 333 | isa = PBXVariantGroup; 334 | children = ( 335 | E34E83062079CD5400BA09DF /* Base */, 336 | ); 337 | name = Main.storyboard; 338 | sourceTree = ""; 339 | }; 340 | /* End PBXVariantGroup section */ 341 | 342 | /* Begin XCBuildConfiguration section */ 343 | E3197F2220E8008900746439 /* Debug */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | BUNDLE_LOADER = "$(TEST_HOST)"; 347 | CODE_SIGN_STYLE = Automatic; 348 | COMBINE_HIDPI_IMAGES = YES; 349 | DEVELOPMENT_TEAM = KQQ77ZBE5E; 350 | INFOPLIST_FILE = MacCacheCleanerTests/Info.plist; 351 | LD_RUNPATH_SEARCH_PATHS = ( 352 | "$(inherited)", 353 | "@executable_path/../Frameworks", 354 | "@loader_path/../Frameworks", 355 | ); 356 | PRODUCT_BUNDLE_IDENTIFIER = com.kaunteya.MacCacheCleanerTests; 357 | PRODUCT_NAME = "$(TARGET_NAME)"; 358 | SWIFT_VERSION = 5.0; 359 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Mac Cache Cleaner.app/Contents/MacOS/Mac Cache Cleaner"; 360 | }; 361 | name = Debug; 362 | }; 363 | E3197F2320E8008900746439 /* Release */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | BUNDLE_LOADER = "$(TEST_HOST)"; 367 | CODE_SIGN_STYLE = Automatic; 368 | COMBINE_HIDPI_IMAGES = YES; 369 | DEVELOPMENT_TEAM = KQQ77ZBE5E; 370 | INFOPLIST_FILE = MacCacheCleanerTests/Info.plist; 371 | LD_RUNPATH_SEARCH_PATHS = ( 372 | "$(inherited)", 373 | "@executable_path/../Frameworks", 374 | "@loader_path/../Frameworks", 375 | ); 376 | PRODUCT_BUNDLE_IDENTIFIER = com.kaunteya.MacCacheCleanerTests; 377 | PRODUCT_NAME = "$(TARGET_NAME)"; 378 | SWIFT_VERSION = 5.0; 379 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Mac Cache Cleaner.app/Contents/MacOS/Mac Cache Cleaner"; 380 | }; 381 | name = Release; 382 | }; 383 | E34E830A2079CD5400BA09DF /* Debug */ = { 384 | isa = XCBuildConfiguration; 385 | buildSettings = { 386 | ALWAYS_SEARCH_USER_PATHS = NO; 387 | CLANG_ANALYZER_NONNULL = YES; 388 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 389 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 390 | CLANG_CXX_LIBRARY = "libc++"; 391 | CLANG_ENABLE_MODULES = YES; 392 | CLANG_ENABLE_OBJC_ARC = YES; 393 | CLANG_ENABLE_OBJC_WEAK = YES; 394 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 395 | CLANG_WARN_BOOL_CONVERSION = YES; 396 | CLANG_WARN_COMMA = YES; 397 | CLANG_WARN_CONSTANT_CONVERSION = YES; 398 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 399 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 400 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 401 | CLANG_WARN_EMPTY_BODY = YES; 402 | CLANG_WARN_ENUM_CONVERSION = YES; 403 | CLANG_WARN_INFINITE_RECURSION = YES; 404 | CLANG_WARN_INT_CONVERSION = YES; 405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 406 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 407 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 409 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 410 | CLANG_WARN_STRICT_PROTOTYPES = YES; 411 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 412 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 413 | CLANG_WARN_UNREACHABLE_CODE = YES; 414 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 415 | CODE_SIGN_IDENTITY = "Mac Developer"; 416 | COPY_PHASE_STRIP = NO; 417 | DEBUG_INFORMATION_FORMAT = dwarf; 418 | ENABLE_STRICT_OBJC_MSGSEND = YES; 419 | ENABLE_TESTABILITY = YES; 420 | GCC_C_LANGUAGE_STANDARD = gnu11; 421 | GCC_DYNAMIC_NO_PIC = NO; 422 | GCC_NO_COMMON_BLOCKS = YES; 423 | GCC_OPTIMIZATION_LEVEL = 0; 424 | GCC_PREPROCESSOR_DEFINITIONS = ( 425 | "DEBUG=1", 426 | "$(inherited)", 427 | ); 428 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 429 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 430 | GCC_WARN_UNDECLARED_SELECTOR = YES; 431 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 432 | GCC_WARN_UNUSED_FUNCTION = YES; 433 | GCC_WARN_UNUSED_VARIABLE = YES; 434 | MACOSX_DEPLOYMENT_TARGET = 10.13; 435 | MTL_ENABLE_DEBUG_INFO = YES; 436 | ONLY_ACTIVE_ARCH = YES; 437 | SDKROOT = macosx; 438 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 439 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 440 | }; 441 | name = Debug; 442 | }; 443 | E34E830B2079CD5400BA09DF /* Release */ = { 444 | isa = XCBuildConfiguration; 445 | buildSettings = { 446 | ALWAYS_SEARCH_USER_PATHS = NO; 447 | CLANG_ANALYZER_NONNULL = YES; 448 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 450 | CLANG_CXX_LIBRARY = "libc++"; 451 | CLANG_ENABLE_MODULES = YES; 452 | CLANG_ENABLE_OBJC_ARC = YES; 453 | CLANG_ENABLE_OBJC_WEAK = YES; 454 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 455 | CLANG_WARN_BOOL_CONVERSION = YES; 456 | CLANG_WARN_COMMA = YES; 457 | CLANG_WARN_CONSTANT_CONVERSION = YES; 458 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 459 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 460 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 461 | CLANG_WARN_EMPTY_BODY = YES; 462 | CLANG_WARN_ENUM_CONVERSION = YES; 463 | CLANG_WARN_INFINITE_RECURSION = YES; 464 | CLANG_WARN_INT_CONVERSION = YES; 465 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 466 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 467 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 468 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 469 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 470 | CLANG_WARN_STRICT_PROTOTYPES = YES; 471 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 472 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 473 | CLANG_WARN_UNREACHABLE_CODE = YES; 474 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 475 | CODE_SIGN_IDENTITY = "Mac Developer"; 476 | COPY_PHASE_STRIP = NO; 477 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 478 | ENABLE_NS_ASSERTIONS = NO; 479 | ENABLE_STRICT_OBJC_MSGSEND = YES; 480 | GCC_C_LANGUAGE_STANDARD = gnu11; 481 | GCC_NO_COMMON_BLOCKS = YES; 482 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 483 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 484 | GCC_WARN_UNDECLARED_SELECTOR = YES; 485 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 486 | GCC_WARN_UNUSED_FUNCTION = YES; 487 | GCC_WARN_UNUSED_VARIABLE = YES; 488 | MACOSX_DEPLOYMENT_TARGET = 10.13; 489 | MTL_ENABLE_DEBUG_INFO = NO; 490 | SDKROOT = macosx; 491 | SWIFT_COMPILATION_MODE = wholemodule; 492 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 493 | }; 494 | name = Release; 495 | }; 496 | E34E830D2079CD5400BA09DF /* Debug */ = { 497 | isa = XCBuildConfiguration; 498 | buildSettings = { 499 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 500 | CODE_SIGN_IDENTITY = "Mac Developer"; 501 | CODE_SIGN_STYLE = Automatic; 502 | COMBINE_HIDPI_IMAGES = YES; 503 | DEVELOPMENT_TEAM = KQQ77ZBE5E; 504 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 505 | GCC_WARN_UNUSED_PARAMETER = YES; 506 | INFOPLIST_FILE = MacCacheCleaner/Info.plist; 507 | LD_RUNPATH_SEARCH_PATHS = ( 508 | "$(inherited)", 509 | "@executable_path/../Frameworks", 510 | ); 511 | MACOSX_DEPLOYMENT_TARGET = 10.13; 512 | PRODUCT_BUNDLE_IDENTIFIER = com.kaunteya.MacCacheCleaner; 513 | PRODUCT_NAME = "$(TARGET_NAME)"; 514 | PROVISIONING_PROFILE_SPECIFIER = ""; 515 | SWIFT_VERSION = 5.0; 516 | }; 517 | name = Debug; 518 | }; 519 | E34E830E2079CD5400BA09DF /* Release */ = { 520 | isa = XCBuildConfiguration; 521 | buildSettings = { 522 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 523 | CODE_SIGN_IDENTITY = "Mac Developer"; 524 | CODE_SIGN_STYLE = Automatic; 525 | COMBINE_HIDPI_IMAGES = YES; 526 | DEVELOPMENT_TEAM = KQQ77ZBE5E; 527 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 528 | GCC_WARN_UNUSED_PARAMETER = YES; 529 | INFOPLIST_FILE = MacCacheCleaner/Info.plist; 530 | LD_RUNPATH_SEARCH_PATHS = ( 531 | "$(inherited)", 532 | "@executable_path/../Frameworks", 533 | ); 534 | MACOSX_DEPLOYMENT_TARGET = 10.13; 535 | PRODUCT_BUNDLE_IDENTIFIER = com.kaunteya.MacCacheCleaner; 536 | PRODUCT_NAME = "$(TARGET_NAME)"; 537 | PROVISIONING_PROFILE_SPECIFIER = ""; 538 | SWIFT_VERSION = 5.0; 539 | }; 540 | name = Release; 541 | }; 542 | /* End XCBuildConfiguration section */ 543 | 544 | /* Begin XCConfigurationList section */ 545 | E3197F2120E8008900746439 /* Build configuration list for PBXNativeTarget "Mac Cache CleanerTests" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | E3197F2220E8008900746439 /* Debug */, 549 | E3197F2320E8008900746439 /* Release */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | E34E82F72079CD5200BA09DF /* Build configuration list for PBXProject "Mac Cache Cleaner" */ = { 555 | isa = XCConfigurationList; 556 | buildConfigurations = ( 557 | E34E830A2079CD5400BA09DF /* Debug */, 558 | E34E830B2079CD5400BA09DF /* Release */, 559 | ); 560 | defaultConfigurationIsVisible = 0; 561 | defaultConfigurationName = Release; 562 | }; 563 | E34E830C2079CD5400BA09DF /* Build configuration list for PBXNativeTarget "Mac Cache Cleaner" */ = { 564 | isa = XCConfigurationList; 565 | buildConfigurations = ( 566 | E34E830D2079CD5400BA09DF /* Debug */, 567 | E34E830E2079CD5400BA09DF /* Release */, 568 | ); 569 | defaultConfigurationIsVisible = 0; 570 | defaultConfigurationName = Release; 571 | }; 572 | /* End XCConfigurationList section */ 573 | }; 574 | rootObject = E34E82F42079CD5200BA09DF /* Project object */; 575 | } 576 | -------------------------------------------------------------------------------- /Mac Cache Cleaner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Mac Cache Cleaner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Mac Cache Cleaner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Mac Cache Cleaner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MacCacheCleaner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 08/04/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | private let cacheListFetcher = CacheFetcher.init(url: .sourceJSONPath) 15 | 16 | private let cacheList = CacheList() 17 | 18 | func applicationDidFinishLaunching(_ aNotification: Notification) { 19 | let mainVC = MainViewController.initialize(cacheList: cacheList) 20 | 21 | NSWindowController 22 | .makeWindowController(contentViewController: mainVC, sceneId: "mainWindowController") 23 | .showWindow(self) 24 | 25 | self.setCacheMainList() 26 | 27 | VersionHandler(githubURL: .latestVersion).showAlertForOldVersion() 28 | } 29 | 30 | private func setCacheMainList() { 31 | cacheListFetcher.fromNetwork(completion: { itemList in 32 | Log.info("Cache definitions fetch completed") 33 | self.cacheList.mainList = itemList 34 | }, failure: { error in 35 | if let error = error { 36 | DispatchQueue.main.async { 37 | NSAlert(error: error).runModal() 38 | } 39 | } 40 | Log.info("Network failed \(error?.localizedDescription ?? "")") 41 | }) 42 | } 43 | 44 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 45 | return true 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_128.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_128@2x.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_16.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_16@2x.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_256.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_256@2x.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_32.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_32@2x.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_512.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_512@2x.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "AppIcon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "AppIcon_16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "AppIcon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "AppIcon_32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "AppIcon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "AppIcon_128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "AppIcon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "AppIcon_256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "AppIcon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "AppIcon_512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "StatusIcon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "StatusIcon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "StatusIcon@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon@2x.png -------------------------------------------------------------------------------- /MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/99192b222ec18526799c8e1a846946ea2c1ad7ef/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon@3x.png -------------------------------------------------------------------------------- /MacCacheCleaner/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // Mac Cache Cleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 12/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension URL { 12 | /// Fetches json which has details of all the cache definitions 13 | static let sourceJSONPath: URL = "https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/master/Source.json" 14 | 15 | // static let sourceJSONPath: URL = "http://0.0.0.0:9111/Source.json" 16 | 17 | /// Fetches info of `latest` maccachecleaner from github 18 | static let latestVersion: URL = "https://api.github.com/repos/kaunteya/maccachecleaner/releases/latest" 19 | } 20 | -------------------------------------------------------------------------------- /MacCacheCleaner/Extensions/FileManager+Size.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FileManager+Size.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 25/06/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension FileManager { 12 | 13 | func isDirectory(_ url: URL) -> Bool { 14 | var isDir : ObjCBool = false 15 | FileManager.default.fileExists(atPath: url.path, isDirectory: &isDir) 16 | return isDir.boolValue 17 | } 18 | 19 | static func remove(_ item: URL) throws { 20 | try FileManager.default.removeItem(at: item) 21 | } 22 | 23 | /// Calculates the size of directory 24 | /// 25 | /// - Parameter url: URL of the directory / file 26 | /// - Returns: Value in bytes 27 | static func sizeOf(_ url: URL) -> Int64 { 28 | if FileManager.default.isDirectory(url) { 29 | var totalSize: Int64 = 0 30 | 31 | let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: nil)! 32 | for a in enumerator { 33 | let f = a as! URL 34 | let gt = try! FileManager.default.attributesOfItem(atPath: f.path) 35 | let size = gt[FileAttributeKey.size] as! Int64 36 | totalSize += size 37 | } 38 | return totalSize 39 | } else { 40 | if let gt = try? FileManager.default.attributesOfItem(atPath: url.path) { 41 | return gt[FileAttributeKey.size] as! Int64 42 | } 43 | return 0 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /MacCacheCleaner/Extensions/NSWindowController+intialize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSWindowController+intialize.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 02/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | extension NSWindowController { 12 | 13 | class func makeWindowController( 14 | contentViewController: NSViewController, 15 | sceneId: String 16 | ) -> NSWindowController { 17 | 18 | let windowController = NSStoryboard.main?.instantiateController( 19 | withIdentifier: sceneId 20 | ) as! NSWindowController 21 | 22 | windowController.contentViewController = contentViewController 23 | return windowController 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MacCacheCleaner/Extensions/URL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL.swift 3 | // Mac Cache Cleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 12/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // This would let us create URL directly from the string 12 | // Eg. let url: URL = "http://abc.com" 13 | // Note: Use this only when URL is local/hard coded. Dont use for URLs that can be in improper format 14 | extension URL : ExpressibleByStringLiteral { 15 | public typealias StringLiteralType = String 16 | 17 | public init(stringLiteral value: StringLiteralType) { 18 | self.init(string: value)! 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MacCacheCleaner/Extensions/URLSession+Result.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLSession+Result.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 30/06/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum Result { 12 | case success(Value) 13 | case failure(Error?) 14 | } 15 | 16 | extension URLSession { 17 | 18 | /// Data fetched from URLSession is decoded using JSONDecoder 19 | func jsonDecodableTask( 20 | with url: URL, 21 | completion: @escaping (Result) -> Void 22 | ) -> URLSessionDataTask { 23 | 24 | return self.dataTask(with: url) { (data, response, error) in 25 | guard error == nil else { 26 | completion(.failure(error!)) 27 | return 28 | } 29 | guard let data = data, let _ = response else { 30 | completion(.failure(nil)) 31 | return 32 | } 33 | 34 | if let decoded = try? JSONDecoder().decode(T.self, from: data) { 35 | completion(.success(decoded)) 36 | } else { 37 | completion(.failure(nil)) 38 | } 39 | } 40 | } 41 | 42 | /// Data fetched from URLSession is serialized using JSONSerialization 43 | func jsonSerializedTask( 44 | with request: URL, 45 | completion: @escaping (Result) -> Void 46 | ) -> URLSessionDataTask { 47 | 48 | return self.dataTask(with: request) { (data, response, error) in 49 | guard error == nil else { 50 | completion(.failure(error!)) 51 | return 52 | } 53 | guard let data = data, let _ = response else { 54 | completion(.failure(nil)) 55 | return 56 | } 57 | if let json = try! JSONSerialization.jsonObject(with: data, options: []) as? T { 58 | completion(.success(json)) 59 | } else { 60 | completion(.failure(nil)) 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MacCacheCleaner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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.2 21 | CFBundleVersion 22 | 5 23 | LSApplicationCategoryType 24 | public.app-category.utilities 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /MacCacheCleaner/MacCacheCleaner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MacCacheCleaner/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 01/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | class MainViewController: NSViewController, StoryboardLoadable { 12 | 13 | @IBOutlet weak var loadingView: NSVisualEffectView! 14 | @IBOutlet var tableViewHandler: TableViewHandler! 15 | 16 | static var sceneIdentifier: String { 17 | return "mainVC" 18 | } 19 | static func initialize(cacheList: CacheList) -> MainViewController { 20 | let mainVC = makeFromStoryboard() 21 | mainVC.tableViewHandler.setCacheList(cacheList) 22 | return mainVC 23 | } 24 | 25 | override func viewDidLoad() { 26 | tableViewHandler.delegate = self 27 | } 28 | } 29 | 30 | extension MainViewController: CacheTableViewDelegate { 31 | func cacheListUpdateStatusChanged(status: CacheList.UpdateStatus) { 32 | Log.info("Update status \(status)") 33 | DispatchQueue.main.async { [weak self] in 34 | self?.loadingView.isHidden = status == .completed 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MacCacheCleaner/Models/CacheItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CacheItem.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 08/04/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct CacheItem: Decodable, Equatable { 12 | 13 | typealias ID = Tagged 14 | 15 | let id: ID 16 | let name: String 17 | let image: URL? 18 | let description: String 19 | let locations: [Location] 20 | } 21 | 22 | extension CacheItem { 23 | func delete(onComplete complete: (() -> Void)? = nil) { 24 | locations.forEach{ try? $0.delete() } 25 | complete?() 26 | } 27 | } 28 | 29 | extension CacheItem: Hashable { 30 | func hash(into hasher: inout Hasher) { 31 | hasher.combine(id) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /MacCacheCleaner/Models/CacheList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CacheList.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 02/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | protocol CacheListDelegate: class { 12 | func gotSizeFor(item: CacheItem) 13 | func itemRemovedCompleted(item: CacheItem) 14 | func cacheListUpdateStatusChanged(status: CacheList.UpdateStatus) 15 | } 16 | 17 | class CacheList { 18 | typealias ItemAndSize = (id: CacheItem.ID, totalSize: Location.Size, sizeMap: Location.SizeMap) 19 | enum UpdateStatus { case started, completed, failed } 20 | 21 | private var listWithSizes = [ItemAndSize]() 22 | 23 | /// List info loaded from Internet 24 | /// Can be updated only from URL response 25 | var mainList: [CacheItem]? { 26 | didSet { 27 | let qos: DispatchQoS.QoSClass = mainList == nil ? .default : .utility 28 | updateSize(queue: .global(qos: qos)) 29 | } 30 | } 31 | 32 | weak var delegate: CacheListDelegate? 33 | 34 | subscript(id: CacheItem.ID) -> CacheItem? { 35 | return mainList?.first(where: { $0.id == id }) 36 | } 37 | } 38 | 39 | extension CacheList { 40 | 41 | func updateSize(queue: DispatchQueue) { 42 | guard let mainList = mainList else { 43 | delegate?.cacheListUpdateStatusChanged(status: .failed) 44 | return 45 | } 46 | delegate?.cacheListUpdateStatusChanged(status: .started) 47 | 48 | let dispatchGroup = DispatchGroup() 49 | mainList.forEach { item in 50 | queue.async { 51 | dispatchGroup.enter() 52 | let sizeMap = item.locations.sizeMap 53 | let totalSize = sizeMap.totalSize 54 | 55 | DispatchQueue.main.async { [unowned self] in 56 | dispatchGroup.leave() 57 | if totalSize.rawValue > 0 { 58 | let itemSize = ItemAndSize(id: item.id, totalSize: totalSize, sizeMap: sizeMap) 59 | self.updateListWithSizes(element: itemSize) 60 | self.delegate?.gotSizeFor(item: item) 61 | } 62 | } 63 | } 64 | } 65 | dispatchGroup.notify(queue: .main) { [unowned self] in 66 | self.delegate?.cacheListUpdateStatusChanged(status: .completed) 67 | } 68 | } 69 | 70 | private func updateListWithSizes(element: ItemAndSize) { 71 | if let index = listWithSizes.firstIndex(where: { $0.id == element.id}) { 72 | listWithSizes[index] = element 73 | } else { 74 | listWithSizes.append(element) 75 | } 76 | listWithSizes.sort { $0.totalSize.rawValue > $1.totalSize.rawValue } 77 | } 78 | 79 | func delete(_ id: CacheItem.ID) { 80 | let cacheItem = self[id]! 81 | // Delete on background queue and call completion on main queue 82 | DispatchQueue.global(qos: .utility).async { 83 | cacheItem.delete(onComplete: { 84 | DispatchQueue.main.async { 85 | self.listWithSizes = self.listWithSizes.filter { $0.id != id } 86 | self.delegate?.itemRemovedCompleted(item: cacheItem) 87 | } 88 | }) 89 | } 90 | } 91 | } 92 | 93 | extension CacheList: Collection { 94 | typealias Index = Int 95 | typealias Element = ItemAndSize 96 | 97 | subscript(position: Int) -> ItemAndSize { 98 | return listWithSizes[position] 99 | } 100 | 101 | func index(after i: Int) -> Int { 102 | return listWithSizes.index(after: i) 103 | } 104 | 105 | var startIndex: CacheList.Index { 106 | return listWithSizes.startIndex 107 | } 108 | var endIndex: CacheList.Index { 109 | return listWithSizes.endIndex 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /MacCacheCleaner/Models/Location.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Location.swift 3 | // Mac Cache Cleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 13/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Location: RawRepresentable, Hashable { 12 | typealias RawValue = URL 13 | typealias Size = Tagged 14 | typealias SizeMap = [Location: Location.Size] 15 | 16 | var rawValue: RawValue 17 | var size: Size { 18 | let size = FileManager.sizeOf(rawValue) 19 | return Size(integerLiteral: size) 20 | } 21 | 22 | func delete() throws { 23 | try FileManager.remove(rawValue) 24 | } 25 | } 26 | 27 | extension Location: Decodable { 28 | init(from decoder: Decoder) throws { 29 | let container = try decoder.singleValueContainer() 30 | let str = try container.decode(String.self) 31 | let expandedPath = NSString(string: str).expandingTildeInPath 32 | self.rawValue = URL(fileURLWithPath: expandedPath, isDirectory: true) 33 | } 34 | } 35 | 36 | extension Tagged where Tag == Location, RawValue == Int64 { 37 | var readable: String { 38 | return ByteCountFormatter().string(fromByteCount: rawValue) 39 | } 40 | } 41 | 42 | extension Array where Element == Location { 43 | var sizeMap: Location.SizeMap { 44 | return reduce(Location.SizeMap()) { 45 | return $0.merging([$1 : $1.size], uniquingKeysWith: {a, b in return a }) 46 | } 47 | } 48 | } 49 | 50 | extension Dictionary where Key == Location, Value == Location.Size { 51 | var totalSize: Location.Size { 52 | let totalSize = values 53 | .map { $0.rawValue} 54 | .reduce(0, +) 55 | return Location.Size(rawValue: totalSize) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /MacCacheCleaner/Others/AutoStartSpinner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutoStartSpinner.swift 3 | // Mac Cache Cleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 12/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | /// Upon setting spinner to AutoStartSpinner, they will start spinning immediately after loaded 12 | class AutoStartSpinner: NSProgressIndicator { 13 | override func awakeFromNib() { 14 | super.awakeFromNib() 15 | self.startAnimation(self) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MacCacheCleaner/Others/CacheFetcher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CacheFetcher.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 02/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct SourceJSON: Decodable { 12 | let version: Int 13 | let items: [CacheItem] 14 | } 15 | 16 | struct CacheFetcher { 17 | let url: URL 18 | 19 | func fromNetwork(completion: @escaping([CacheItem]) -> Void, 20 | failure: ((Error?) -> Void)?) { 21 | 22 | URLSession.shared.jsonDecodableTask(with: url) { (result:Result) in 23 | switch result { 24 | case .success(let decoded): 25 | assert(decoded.version == 1) 26 | completion(decoded.items) 27 | case .failure(let error): failure?(error) 28 | } 29 | }.resume() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MacCacheCleaner/Others/Log.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Log.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 05/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | enum Log { 11 | static func info(_ f: String) { 12 | print(f) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MacCacheCleaner/Others/Other.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Other.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 27/06/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | extension NSStackView { 12 | func removeAllArrangedSubViews() { 13 | arrangedSubviews.forEach(removeView) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MacCacheCleaner/Others/StoryboardLoadable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoryboardLoadable.swift 3 | // Mac Cache Cleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 13/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | /// Lets NSViewController subclass be created from Storyboard 12 | protocol StoryboardLoadable { 13 | static var storyboard: NSStoryboard {get} 14 | static var sceneIdentifier: String {get} 15 | static func makeFromStoryboard() -> Self 16 | } 17 | 18 | extension StoryboardLoadable { 19 | static var storyboard: NSStoryboard { 20 | return NSStoryboard.main! 21 | } 22 | 23 | static func makeFromStoryboard() -> Self { 24 | return storyboard.instantiateController(withIdentifier: sceneIdentifier) as! Self 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MacCacheCleaner/Others/Tagged.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tagged.swift 3 | // Mac Cache Cleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 07/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Tagged { 12 | let rawValue: RawValue 13 | } 14 | 15 | extension Tagged: Decodable where RawValue: Decodable { 16 | init(from decoder: Decoder) throws { 17 | let container = try decoder.singleValueContainer() 18 | self.init(rawValue: try container.decode(RawValue.self)) 19 | } 20 | } 21 | 22 | extension Tagged: Equatable where RawValue: Equatable { 23 | static func ==(lhs: Tagged, rhs: Tagged) -> Bool { 24 | return lhs.rawValue == rhs.rawValue 25 | } 26 | } 27 | 28 | extension Tagged: Hashable where RawValue: Hashable { 29 | func hash(into hasher: inout Hasher) { 30 | hasher.combine(rawValue) 31 | } 32 | } 33 | 34 | extension Tagged: ExpressibleByIntegerLiteral where RawValue: ExpressibleByIntegerLiteral { 35 | typealias IntegerLiteralType = RawValue.IntegerLiteralType 36 | init(integerLiteral value: RawValue.IntegerLiteralType) { 37 | self.init(rawValue: RawValue(integerLiteral: value)) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /MacCacheCleaner/TableViewHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableDelegateDataSource.swift 3 | // Mac Cache Cleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 10/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | protocol CacheTableViewDelegate: class { 12 | /// Status update is notified when started, completed, failed 13 | func cacheListUpdateStatusChanged(status: CacheList.UpdateStatus) 14 | } 15 | 16 | class TableViewHandler: NSObject { 17 | var cacheList: CacheList! 18 | weak var delegate: CacheTableViewDelegate? 19 | private let cacheTableCell = NSUserInterfaceItemIdentifier(rawValue: "cacheCell") 20 | 21 | @IBOutlet weak var tableView: NSTableView! 22 | 23 | func setCacheList(_ cacheList: CacheList) { 24 | self.cacheList = cacheList 25 | self.cacheList.delegate = self 26 | } 27 | } 28 | 29 | extension TableViewHandler: NSTableViewDelegate, NSTableViewDataSource { 30 | func numberOfRows(in tableView: NSTableView) -> Int { 31 | return cacheList.count 32 | } 33 | 34 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 35 | let cell = tableView.makeView(withIdentifier: cacheTableCell, owner: nil) as! CacheTableCellView 36 | let (itemId, totalSize, sizeMap) = cacheList[row] 37 | let cacheItem = cacheList[itemId]! 38 | 39 | cell.updateFor(cacheItem: cacheItem, totalSize: totalSize, sizeMap: sizeMap, row: row) 40 | cell.delegate = self 41 | return cell 42 | } 43 | } 44 | 45 | extension TableViewHandler: CacheCellViewDelegate { 46 | func userActionClearLocation(cacheId: CacheItem.ID, location: String, row: Int) { 47 | } 48 | 49 | func userActionClearCache(cacheId: CacheItem.ID, row: Int) { 50 | Log.info("Remove \(cacheList[cacheId]!.name)") 51 | let view = tableView.view(atColumn: 0, row: row, makeIfNecessary: false) 52 | as! CacheTableCellView 53 | view.showDeleteView() 54 | 55 | cacheList.delete(cacheId) 56 | } 57 | } 58 | 59 | extension TableViewHandler: CacheListDelegate { 60 | func cacheListUpdateStatusChanged(status: CacheList.UpdateStatus) { 61 | delegate?.cacheListUpdateStatusChanged(status: status) 62 | } 63 | 64 | func itemRemovedCompleted(item: CacheItem) { 65 | tableView.reloadData() 66 | } 67 | 68 | func gotSizeFor(item: CacheItem) { 69 | tableView.reloadData() 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /MacCacheCleaner/VersionHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VersionHandler.swift 3 | // Mac Cache Cleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 12/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | struct VersionHandler { 12 | let githubURL: URL 13 | 14 | private func latestVersion(completion: @escaping (String) -> Void) { 15 | URLSession.shared.jsonSerializedTask(with: githubURL) { (result: Result<[String: Any]>) in 16 | switch result { 17 | case .success(let json): 18 | if let version = json["tag_name"] as? String { 19 | completion(version) 20 | } 21 | case .failure(_): break 22 | } 23 | }.resume() 24 | } 25 | 26 | func showAlertForOldVersion() { 27 | latestVersion { version in 28 | let current = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String 29 | if version != current { 30 | Log.info("Latest Version = \(version) current = \(current)") 31 | DispatchQueue.main.async(execute: self.showAlert) 32 | } 33 | } 34 | } 35 | 36 | private func showAlert() { 37 | let alert = NSAlert() 38 | alert.alertStyle = .warning 39 | 40 | alert.addButton(withTitle: "Close") 41 | alert.addButton(withTitle: "Download") 42 | 43 | alert.messageText = "New version available!!" 44 | alert.informativeText = "Please update your app for latest features & bug fixes" 45 | let response = alert.runModal() 46 | 47 | if response == .alertSecondButtonReturn { 48 | NSWorkspace.shared.open("https://github.com/kaunteya/MacCacheCleaner") 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /MacCacheCleaner/View/Base.lproj/Main.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 | 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 | Default 531 | 532 | 533 | 534 | 535 | 536 | 537 | Left to Right 538 | 539 | 540 | 541 | 542 | 543 | 544 | Right to Left 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | Default 556 | 557 | 558 | 559 | 560 | 561 | 562 | Left to Right 563 | 564 | 565 | 566 | 567 | 568 | 569 | Right to Left 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 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 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 922 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | -------------------------------------------------------------------------------- /MacCacheCleaner/View/CacheTableCellView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CacheTableCellView.swift 3 | // MacCacheCleaner 4 | // 5 | // Created by Kaunteya Suryawanshi on 01/07/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | //import SDWebImage 11 | 12 | protocol CacheCellViewDelegate:class { 13 | func userActionClearCache(cacheId: CacheItem.ID, row: Int) 14 | func userActionClearLocation(cacheId: CacheItem.ID, location: String, row: Int) 15 | } 16 | 17 | class CacheTableCellView: NSTableCellView { 18 | weak var delegate: CacheCellViewDelegate? 19 | @IBOutlet weak var deleteLoadingView: NSStackView! 20 | @IBOutlet weak var locationsStackView: NSStackView! 21 | 22 | @IBOutlet weak var nameLabel: NSTextField! 23 | @IBOutlet weak var sizeLabel: NSTextField! 24 | @IBOutlet weak var descriptionLabel: NSTextField! 25 | @IBOutlet weak var clearButton: NSButton! 26 | // @IBOutlet weak var cacheImageView: NSImageView! 27 | 28 | var id: CacheItem.ID! 29 | var rowIndex: Int! 30 | 31 | @IBAction func clearAction(_ sender: NSButton) { 32 | delegate?.userActionClearCache(cacheId: id, row: rowIndex) 33 | } 34 | 35 | func updateFor(cacheItem: CacheItem, totalSize: Location.Size, sizeMap: Location.SizeMap, row: Int) { 36 | id = cacheItem.id 37 | rowIndex = row 38 | nameLabel.stringValue = cacheItem.name 39 | sizeLabel.stringValue = totalSize.readable 40 | descriptionLabel.stringValue = cacheItem.description 41 | 42 | locationsStackView.removeAllArrangedSubViews() 43 | cacheItem.locations 44 | .map {location in 45 | let readableSize = sizeMap[location]!.readable 46 | return LocationView(location.rawValue.relativePath, size: readableSize, onDelete: { }) } 47 | .forEach(locationsStackView.addArrangedSubview) 48 | 49 | clearButton.isHidden = false 50 | deleteLoadingView.isHidden = true 51 | } 52 | 53 | func showDeleteView() { 54 | clearButton.isHidden = true 55 | deleteLoadingView.isHidden = false 56 | } 57 | } 58 | 59 | class LocationView: NSStackView { 60 | let onDelete: () -> Void 61 | let strValue: String 62 | init(_ location: String, size: String, onDelete: @escaping () -> Void) { 63 | self.strValue = location 64 | self.onDelete = onDelete 65 | super.init(frame: .zero) 66 | let button = NSButton(image: NSImage(named: NSImage.touchBarDeleteTemplateName)!, target: self, action: #selector(deleteAction)) 67 | button.isBordered = false 68 | button.bezelStyle = .roundRect 69 | self.addArrangedSubview(LocationLabel(location)) 70 | self.addArrangedSubview(LocationLabel(size)) 71 | // self.addArrangedSubview(button) 72 | self.orientation = .horizontal 73 | self.spacing = 2 74 | } 75 | 76 | required init?(coder decoder: NSCoder) { 77 | fatalError("init(coder:) has not been implemented") 78 | } 79 | @objc func deleteAction() { 80 | print("Delete \(strValue)") 81 | } 82 | } 83 | 84 | fileprivate class LocationLabel: NSTextField { 85 | convenience init(_ str: String) { 86 | self.init(labelWithString: str) 87 | self.font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize) 88 | self.textColor = NSColor.tertiaryLabelColor 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /MacCacheCleanerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /MacCacheCleanerTests/JSONTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSONTests.swift 3 | // MacCacheCleanerTests 4 | // 5 | // Created by Kaunteya Suryawanshi on 30/06/18. 6 | // Copyright © 2018 Kaunteya Suryawanshi. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | extension String { 12 | var jsonToDictionary: [String: Any] { 13 | let data = self.data(using: .utf8)! 14 | return try! JSONSerialization.jsonObject(with: data, options: []) as! [String : Any] 15 | } 16 | } 17 | 18 | class JSONTests: XCTestCase { 19 | 20 | func JSONFrom(file: String) -> [String: Any] { 21 | let bundle = Bundle(for: type(of: self)) 22 | let path = bundle.path(forResource: file, ofType: "json")! 23 | let url = URL(fileURLWithPath: path) 24 | let str = try! String(contentsOf: url, encoding: .utf8) 25 | return str.jsonToDictionary 26 | } 27 | 28 | 29 | func testJSONFileVersion() { 30 | let file = JSONFrom(file: "Source") 31 | XCTAssertNotNil(file["version"]) 32 | } 33 | 34 | func testList() { 35 | let file = JSONFrom(file: "Source") 36 | XCTAssertNotNil(file["items"] as? [[String : Any]]) 37 | let list = file["items"] as! [[String : Any]] 38 | 39 | let dictKeys = Set([ "id", "name", "description", "locations" ]) 40 | list.forEach { itemDict in 41 | XCTAssert(Set(itemDict.keys).isSuperset(of: dictKeys), itemDict.description) 42 | XCTAssertNotNil(itemDict["locations"] as! [String]) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | #platform : osx, 10.13 2 | 3 | target 'Mac Cache Cleaner' do 4 | use_frameworks! 5 | # pod 'SDWebImage', '~> 4.0' 6 | # pod 'ProgressKit' 7 | end 8 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODFILE CHECKSUM: 47cc3d308a8c74b3352316d955575dee40edc2af 2 | 3 | COCOAPODS: 1.5.3 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ### Add more Cache definitions 7 | More cache definitions can be added in [Source.json](Source.json) 8 | 9 | # Other Apps for Mac 10 | Apart from making Open source libraries I also make apps for Mac OS. Please have a look. 11 | 12 | ## [Lexi](https://apps.apple.com/tr/app/lexi-visual-json-browser/id1462580127?mt=12) 13 | Lexi is a split screen app that lets you browse large JSON with ease. 14 | 15 | It also has other featuers like `Prettify JSON`, `Minify JSON` `Copy JSON Path` and `Pin Large JSON` to narrow your visibility 16 | 17 | [View on Mac AppStore](https://apps.apple.com/tr/app/lexi-visual-json-browser/id1462580127?mt=12) 18 | 19 | ## [Quick Note](https://apps.apple.com/in/app/quicknote-one-click-notes/id1472935217?mt=12) 20 | Quick Note is a Mac OS app, lets you quickly add text either from Menu bar or from Shortcut. 21 | 22 | The text floats on other windows so that they are always visible 23 | 24 | It also supports `Auto Save` and `Pinned Notes` 25 | 26 | [View on Mac AppStore](https://apps.apple.com/in/app/quicknote-one-click-notes/id1472935217?mt=12) 27 | -------------------------------------------------------------------------------- /Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "items": [ 4 | { 5 | "id": "cocoapod", 6 | "name": "Cocoapods", 7 | "description": "CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects.", 8 | "homepage": "https://cocoapods.org/", 9 | "image": "https://pbs.twimg.com/profile_images/378800000632309165/e1cbdef9d4b11484049a033886578e54_400x400.png", 10 | "locations": [ 11 | "~/Library/Caches/CocoaPods" 12 | ] 13 | }, 14 | { 15 | "id": "carthage", 16 | "name": "Carthage", 17 | "description": "A simple, decentralized dependency manager for Cocoa", 18 | "homepage": "https://github.com/Carthage/Carthage", 19 | "locations": [ 20 | "~/Library/Caches/org.carthage.CarthageKit" 21 | ] 22 | }, 23 | { 24 | "id": "homebrew", 25 | "name": "Homebrew", 26 | "description": "The missing package manager for macOS", 27 | "homepage": "https://brew.sh/", 28 | "image": "https://brew.sh/img/homebrew-256x256.png", 29 | "locations": [ 30 | "~/Library/Caches/Homebrew", 31 | "~/Library/Logs/Homebrew/" 32 | ] 33 | }, 34 | { 35 | "id": "npm", 36 | "name": "npm", 37 | "description": "npm is the package manager for JavaScript and the world’s largest software registry.", 38 | "homepage": "https://www.npmjs.com/", 39 | "image": "https://pbs.twimg.com/profile_images/765333670366355456/q5ACQ8i3_400x400.jpg", 40 | "locations": [ 41 | "~/.npm" 42 | ] 43 | }, 44 | { 45 | "id": "xcode-derived", 46 | "name": "Xcode Derived Data", 47 | "description": "Place where Xcode stores all kinds of intermediate build results, generated indexes etc", 48 | "image": "https://pbs.twimg.com/profile_images/925502788032798721/qbxHDQKt_400x400.jpg", 49 | "locations": [ 50 | "~/Library/Developer/Xcode/DerivedData" 51 | ] 52 | }, 53 | { 54 | "id": "yarn", 55 | "name": "Yarn", 56 | "homepage": "https://yarnpkg.com/lang/en/", 57 | "image": "https://raw.githubusercontent.com/yarnpkg/assets/master/yarn-kitten-full.png", 58 | "description": "Fast, Reliable, and Secure dependency management.", 59 | "locations": [ 60 | "~/Library/Caches/Yarn" 61 | ] 62 | }, 63 | { 64 | "id": "chrome", 65 | "name": "Google Chrome", 66 | "description": "One fast, simple, and secure browser for all your devices.", 67 | "homepage": "https://www.google.com/chrome/", 68 | "image": "https://www.google.com/chrome/static/images/chrome-logo.svg", 69 | "locations": [ 70 | "~/Library/Caches/Google/Chrome", 71 | "~/Library/Application Support/Google/Chrome", 72 | "~/Library/Caches/com.google.Chrome" 73 | ] 74 | }, 75 | { 76 | "id": "firefox", 77 | "name": "Mozilla Firefox", 78 | "description": "Firefox is a free and open-source web browser.", 79 | "homepage": "https://www.mozilla.org", 80 | "image": "https://www.mozilla.org/media/img/logos/firefox/logo-quantum-wordmark-white-high-res.3ccf0070280e.png", 81 | "locations": [ 82 | "~/Library/Caches/Firefox", 83 | "~/Library/Caches/org.mozilla.firefox" 84 | ] 85 | } 86 | ] 87 | } 88 | --------------------------------------------------------------------------------