├── Images
├── AppWindow.png
└── AppIcon100x100.png
├── Podfile.lock
├── MacCacheCleaner
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── AppIcon_128.png
│ │ ├── AppIcon_16.png
│ │ ├── AppIcon_256.png
│ │ ├── AppIcon_32.png
│ │ ├── AppIcon_512.png
│ │ ├── AppIcon_128@2x.png
│ │ ├── AppIcon_16@2x.png
│ │ ├── AppIcon_256@2x.png
│ │ ├── AppIcon_32@2x.png
│ │ ├── AppIcon_512@2x.png
│ │ └── Contents.json
│ └── StatusIcon.imageset
│ │ ├── StatusIcon.png
│ │ ├── StatusIcon@2x.png
│ │ ├── StatusIcon@3x.png
│ │ └── Contents.json
├── MacCacheCleaner.entitlements
├── Others
│ ├── Log.swift
│ ├── Other.swift
│ ├── AutoStartSpinner.swift
│ ├── StoryboardLoadable.swift
│ ├── CacheFetcher.swift
│ └── Tagged.swift
├── Extensions
│ ├── URL.swift
│ ├── NSWindowController+intialize.swift
│ ├── FileManager+Size.swift
│ └── URLSession+Result.swift
├── Constants.swift
├── Models
│ ├── CacheItem.swift
│ ├── Location.swift
│ └── CacheList.swift
├── MainViewController.swift
├── Info.plist
├── AppDelegate.swift
├── VersionHandler.swift
├── TableViewHandler.swift
└── View
│ ├── CacheTableCellView.swift
│ └── Base.lproj
│ └── Main.storyboard
├── Podfile
├── Mac Cache Cleaner.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Mac Cache Cleaner.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── project.pbxproj
├── .gitignore
├── MacCacheCleanerTests
├── Info.plist
└── JSONTests.swift
├── LICENSE
├── README.md
└── Source.json
/Images/AppWindow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/Images/AppWindow.png
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODFILE CHECKSUM: 47cc3d308a8c74b3352316d955575dee40edc2af
2 |
3 | COCOAPODS: 1.5.3
4 |
--------------------------------------------------------------------------------
/Images/AppIcon100x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/Images/AppIcon100x100.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_128.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_16.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_256.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_32.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_512.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_128@2x.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_16@2x.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_256@2x.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_32@2x.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/AppIcon.appiconset/AppIcon_512@2x.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon@2x.png
--------------------------------------------------------------------------------
/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kaunteya/MacCacheCleaner/HEAD/MacCacheCleaner/Assets.xcassets/StatusIcon.imageset/StatusIcon@3x.png
--------------------------------------------------------------------------------
/Mac Cache Cleaner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MacCacheCleaner/MacCacheCleaner.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Mac Cache Cleaner.xcodeproj/project.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/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 |
--------------------------------------------------------------------------------
/Mac Cache Cleaner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/MacCacheCleaner/View/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
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 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
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 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
--------------------------------------------------------------------------------