├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── .swift-version ├── .swiftlint.yml ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── Sketch Cache Cleaner.xcodeproj └── project.pbxproj ├── Sketch Cache Cleaner ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── Contents.json │ ├── bg.imageset │ │ ├── Contents.json │ │ └── bg.pdf │ ├── boxWithSketch.imageset │ │ ├── Contents.json │ │ └── boxWithSketch.pdf │ ├── cleared.imageset │ │ ├── Contents.json │ │ └── cleared.pdf │ ├── closedBox.imageset │ │ ├── Contents.json │ │ └── closedBox.pdf │ ├── facebookButton.imageset │ │ ├── Contents.json │ │ └── facebookButton.pdf │ ├── loader.imageset │ │ ├── Contents.json │ │ └── loader.png │ ├── note.imageset │ │ ├── Contents.json │ │ └── note.pdf │ ├── openBox.imageset │ │ ├── Contents.json │ │ └── openBox.pdf │ ├── start.imageset │ │ ├── Contents.json │ │ └── start2.pdf │ └── tweeterButton.imageset │ │ ├── Contents.json │ │ └── tweeterButton.pdf ├── Controllers │ └── MainViewController.swift ├── Extensions │ ├── NSButton+Extensions.swift │ ├── NSFont+Extensions.swift │ ├── NSView+Extensions.swift │ └── String+Extensions.swift ├── Info.plist ├── Main.storyboard ├── SanFranciscoDisplay-Semibold.otf ├── Scripts │ ├── calculate_cache_size.sh │ ├── clear_cache.sh │ └── stop_cache.sh ├── Utils │ ├── ButtonText.swift │ ├── Colors.swift │ ├── Environment.swift │ ├── STPrivilegedTask.h │ ├── STPrivilegedTask.m │ ├── Share.swift │ └── Sketch Cache Cleaner-Bridging-Header.h └── Views │ └── MainWindow.swift ├── assets ├── RELEASE_NOTES.md ├── RELEASE_NOTES.pdf ├── Sketch Cache Cleaner.md ├── SketchCacheCleaner.sketch ├── Sketch_Cache_Cleaner_Logo.png └── catalina │ ├── catalina_1.png │ ├── catalina_2.png │ ├── catalina_3.png │ ├── catalina_4.png │ └── catalina_5.png └── docs └── index.html /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: minikin 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### macOS ### 2 | *.DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | ### Objective-C ### 30 | # Xcode 31 | # 32 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 33 | 34 | ## Build generated 35 | build/ 36 | DerivedData/ 37 | 38 | ## Various settings 39 | *.pbxuser 40 | !default.pbxuser 41 | *.mode1v3 42 | !default.mode1v3 43 | *.mode2v3 44 | !default.mode2v3 45 | *.perspectivev3 46 | !default.perspectivev3 47 | xcuserdata/ 48 | 49 | ## Other 50 | *.moved-aside 51 | *.xccheckout 52 | *.xcscmblueprint 53 | 54 | ## Obj-C/Swift specific 55 | *.hmap 56 | *.ipa 57 | *.dSYM.zip 58 | *.dSYM 59 | 60 | # CocoaPods 61 | # 62 | # We recommend against adding the Pods directory to your .gitignore. However 63 | # you should judge for yourself, the pros and cons are mentioned at: 64 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 65 | # 66 | # Pods/ 67 | 68 | # Carthage 69 | # 70 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 71 | # Carthage/Checkouts 72 | 73 | Carthage/Build 74 | 75 | # fastlane 76 | # 77 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 78 | # screenshots whenever they are needed. 79 | # For more information about the recommended setup visit: 80 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 81 | 82 | fastlane/report.xml 83 | fastlane/Preview.html 84 | fastlane/screenshots 85 | fastlane/test_output 86 | 87 | # Code Injection 88 | # 89 | # After new code Injection tools there's a generated folder /iOSInjectionProject 90 | # https://github.com/johnno1962/injectionforxcode 91 | 92 | iOSInjectionProject/ 93 | 94 | ### Objective-C Patch ### 95 | 96 | ### Swift ### 97 | # Xcode 98 | # 99 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 100 | 101 | ## Build generated 102 | 103 | ## Various settings 104 | 105 | ## Other 106 | 107 | ## Obj-C/Swift specific 108 | 109 | ## Playgrounds 110 | timeline.xctimeline 111 | playground.xcworkspace 112 | 113 | # Swift Package Manager 114 | # 115 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 116 | # Packages/ 117 | # Package.pins 118 | .build/ 119 | 120 | # CocoaPods 121 | # 122 | # We recommend against adding the Pods directory to your .gitignore. However 123 | # you should judge for yourself, the pros and cons are mentioned at: 124 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 125 | # 126 | # Pods/ 127 | 128 | # Carthage 129 | # 130 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 131 | # Carthage/Checkouts 132 | 133 | 134 | # fastlane 135 | # 136 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 137 | # screenshots whenever they are needed. 138 | # For more information about the recommended setup visit: 139 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 140 | 141 | 142 | ### Xcode ### 143 | build 144 | *.xcodeproj/* 145 | !*.xcodeproj/project.pbxproj 146 | !*.xcworkspace/contents.xcworkspacedata 147 | /*.gcno 148 | 149 | ### VisualStudioCode ### 150 | .vscode/* 151 | !.vscode/settings.json 152 | !.vscode/tasks.json 153 | !.vscode/launch.json 154 | !.vscode/extensions.json 155 | .history 156 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.2 -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - vertical_parameter_alignment 3 | excluded: # paths to ignore during linting. Takes precedence over `included`. 4 | - Carthage 5 | - Pods 6 | # configurable rules can be customized from this configuration file 7 | # binary rules can set their severity level 8 | force_cast: warning # implicitly 9 | force_try: 10 | severity: warning # explicitly 11 | # rules that have both warning and error levels, can set just the warning level 12 | # implicitly 13 | line_length: 200 14 | # they can set both implicitly with an array 15 | type_body_length: 16 | - 300 # warning 17 | - 400 # error 18 | # or they can set both explicitly 19 | file_length: 20 | warning: 500 21 | error: 1200 22 | # naming rules can set warnings/errors for min_length and max_length 23 | # additionally they can set excluded names 24 | type_name: 25 | min_length: 3 # only warning 26 | max_length: # warning and error 27 | warning: 40 28 | error: 50 29 | excluded: iPhone # excluded via string 30 | identifier_name: 31 | min_length: # only min_length 32 | error: 2 # only error 33 | excluded: # excluded via string array 34 | - x 35 | - y 36 | - id 37 | - URL 38 | reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji) -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | osx_image: xcode9.2 3 | branches: 4 | only: 5 | - master 6 | env: 7 | global: 8 | - LC_CTYPE=en_US.UTF-8 9 | - LANG=en_US.UTF-8 10 | - WORKSPACE=Sketch\ Cache\ Cleaner.xcodeproj 11 | - MACOS_SCHEME="Sketch Cache Cleaner" 12 | matrix: 13 | - DESTINATION="arch=x86_64" SCHEME="$MACOS_SCHEME" RUN_TESTS="NO" 14 | script: 15 | - set -o pipefail 16 | - xcodebuild -version 17 | - xcodebuild -showsdks -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## Changelog 6 | 7 | ## [1.0.7] - 2020-30-03 8 | 9 | - Add macOS Catalina support 10 | - Bump minimum macOS version to 10.13 11 | - Build with Xcode 11.4 12 | 13 | ### Changed 14 | 15 | ## [1.0.5] - 2019-05-02 16 | 17 | ### Changed 18 | 19 | - Migrate to Swift 5 20 | 21 | ## [1.0.4] - 2018-10-21 22 | 23 | ### Changed 24 | 25 | - Build with Xcode 10 and macOS Mojave 26 | - Migrate to Swift 4.2 27 | 28 | ## [1.0.3] - 2018-03-27 29 | 30 | ### Added 31 | 32 | - Add social sharing 33 | 34 | ### Changed 35 | 36 | - Code refactor 37 | - Build with new Xcode's build system 38 | 39 | ## [1.0.2] - 2017-09-24 40 | 41 | ### Changed 42 | 43 | - Update to Swift 4 44 | - Compiled with Xcode 9 45 | 46 | ## [1.0.1] - 2017-07-14 47 | 48 | ### Fixed 49 | 50 | - Fix compatibility issues with 10.11, 10.12beta 51 | 52 | ## [1.0.0] - 2017-07-11 53 | 54 | - Initial release 55 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at djminikin@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Preparing for development 2 | 3 | 1. Make sure you have [Xcode](https://developer.apple.com/xcode/) installed. 4 | 2. Check out this repository. 5 | 3. Open `Sketch Cache Cleaner.xcodeproj` and start hacking! 6 | 7 | ## About contributions 8 | 9 | There are multiple ways you can contribute to this project. 10 | 11 | The easiest way to contribute is to report possible bugs, request features, [discuss ideas](https://github.com/yo-op/sketchcachecleaner/issues) and share excitement about this project. 12 | 13 | You can also make pull requests. Other than bug fixes, please make sure you discuss your contribution in Issues first. 14 | 15 | ## Submitting a Pull Request 16 | 17 | When submitting new code, please make sure that it is backed by tests. 18 | 19 | ## Developer's Certificate of Origin 1.1 20 | 21 | By making a contribution to this project, I certify that: 22 | 23 | - (a) The contribution was created in whole or in part by me and I 24 | have the right to submit it under the open source license 25 | indicated in the file; or 26 | 27 | - (b) The contribution is based upon previous work that, to the best 28 | of my knowledge, is covered under an appropriate open source 29 | license and I have the right under that license to submit that 30 | work with modifications, whether created in whole or in part 31 | by me, under the same open source license (unless I am 32 | permitted to submit under a different license), as indicated 33 | in the file; or 34 | 35 | - (c) The contribution was provided directly to me by some other 36 | person who certified (a), (b) or (c) and I have not modified 37 | it. 38 | 39 | - (d) I understand and agree that this project and the contribution 40 | are public and that a record of the contribution (including all 41 | personal information I submit with it, including my sign-off) is 42 | maintained indefinitely and may be redistributed consistent with 43 | this project or the open source license(s) involved. 44 | 45 | *Wording of statement copied from [elinux.org](http://elinux.org/Developer_Certificate_Of_Origin)* 46 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Expected behaviour 2 | ### Actual behaviour 3 | ### Steps to reproduce the behaviour 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Sasha Prokhorenko & Yuriy Oparenko 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 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | # How Has This Been Tested? 17 | 18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. 19 | # Checklist: 20 | 21 | - [ ] I have performed a self-review of my own code 22 | - [ ] I have commented my code, particularly in hard-to-understand areas 23 | - [ ] I have made corresponding changes to the documentation 24 | - [ ] My changes generate no new warnings 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine) 2 | 3 |

4 | 5 | Sketch Cache Cleaner 6 | 7 | 8 | Sketch Cache Cleaner on Producthunt 9 | 10 |

11 | 12 |

13 | Sketch Cache Cleaner is a macOS app that deletes hidden Sketch history files that can take a lot of space on your hard drive and that you would probably never use. 14 |

15 | 16 |

17 | 18 | Sketch Cache Cleaner is released under the MIT license. 19 | 20 | 21 | Current Build Status. 22 | 23 | 24 | PRs welcome! 25 | 26 |

27 | 28 |

29 | 30 | Platform 31 | 32 | 33 | 34 | Version 35 | 36 |

37 | 38 |

39 | 40 | Sketch Cache Cleaner 41 | 42 |

43 | 44 | --- 45 | 46 | 1. [Warning](#warning) 47 | 2. [System Requirements](#system-requirements) 48 | 3. [Changelog](https://github.com/yo-op/sketchcachecleaner/blob/master/CHANGELOG.md) 49 | 4. [Tips](#tips) 50 | 5. [Authors](#authors) 51 | 6. [License](#license) 52 | 53 | --- 54 | 55 | ## Warning 56 | 57 | The app idea inspired by two blog posts: [How Sketch took over 200GB of our MacBooks](https://medium.com/@thomasdegry/how-sketch-took-over-200gb-of-our-macbooks-cb7dd10c8163) & [How to recover 50 GB or even more by deleting Sketch caches files](https://medium.com/sketch-app-sources/how-to-recover-50-go-or-even-more-by-deleting-sketch-caches-files-e5829dba20e1) 58 | 59 | Please, read them in case you want to know how it works. 60 | 61 | If your **workflow** relies on **automatic versioning** by macOS 62 | (Time Machine etc.) - **DO NOT USE THIS APP!** 63 | 64 | The app will remove all files in folder: /.DocumentRevisions-V100/ 65 | 66 | --- 67 | 68 | ### System Requirements 69 | 70 | - macOS 10.13+ 71 | - Xcode 11.4+ 72 | - Swift 5.2+ 73 | 74 | --- 75 | 76 | ### Authors 77 | 78 | Idea & design: [Yuriy Oparenko](http://oparenko.com/) 79 | 80 | Development: [Sasha Prokhorenko](https://twitter.com/minikin) 81 | 82 | --- 83 | 84 | ### Tips 85 | 86 | - Use this app wisely. 87 | - Reboot your Mac after app use. 88 | 89 | --- 90 | 91 | ### License 92 | 93 | Sketch Cache Cleaner is distributed under the [MIT license](https://github.com/yo-op/sketchcachecleaner/blob/master/LICENSE.md). 94 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 035AF2A11F0585FB003CD85B /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035AF2A01F0585FB003CD85B /* MainViewController.swift */; }; 11 | 038FCAE91F058A2100755E96 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 038FCAE81F058A2100755E96 /* Main.storyboard */; }; 12 | CE109E5D1F05A01400C4BF25 /* SanFranciscoDisplay-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = CE109E5C1F05A01400C4BF25 /* SanFranciscoDisplay-Semibold.otf */; }; 13 | CE25F7D71E490FA00049CF23 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE25F7D61E490FA00049CF23 /* AppDelegate.swift */; }; 14 | CE25F7DB1E490FA00049CF23 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CE25F7DA1E490FA00049CF23 /* Assets.xcassets */; }; 15 | CE25F7EB1E4914340049CF23 /* calculate_cache_size.sh in Resources */ = {isa = PBXBuildFile; fileRef = CE25F7EA1E4914340049CF23 /* calculate_cache_size.sh */; }; 16 | CE25F7ED1E49145A0049CF23 /* clear_cache.sh in Resources */ = {isa = PBXBuildFile; fileRef = CE25F7EC1E49145A0049CF23 /* clear_cache.sh */; }; 17 | CE25F7F21E4915190049CF23 /* STPrivilegedTask.m in Sources */ = {isa = PBXBuildFile; fileRef = CE25F7F01E4915190049CF23 /* STPrivilegedTask.m */; }; 18 | CE25F7F41E491BE30049CF23 /* stop_cache.sh in Resources */ = {isa = PBXBuildFile; fileRef = CE25F7F31E491BE30049CF23 /* stop_cache.sh */; }; 19 | CEA190B11F02FE3B00C9F30A /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA190B01F02FE3B00C9F30A /* Environment.swift */; }; 20 | FC4D46CD1FE92BE10012B681 /* NSFont+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC4D46CC1FE92BE10012B681 /* NSFont+Extensions.swift */; }; 21 | FC4D46CF1FE92C770012B681 /* NSView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC4D46CE1FE92C770012B681 /* NSView+Extensions.swift */; }; 22 | FC4D46D11FE92C940012B681 /* NSButton+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC4D46D01FE92C940012B681 /* NSButton+Extensions.swift */; }; 23 | FC4D46D31FE92CBA0012B681 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC4D46D21FE92CBA0012B681 /* String+Extensions.swift */; }; 24 | FC4D46D61FE92E7B0012B681 /* MainWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC4D46D51FE92E7B0012B681 /* MainWindow.swift */; }; 25 | FC81FE04206A80CB00BA1282 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC81FE03206A80CB00BA1282 /* Colors.swift */; }; 26 | FCB22D2C201FC4F40054F43E /* Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCB22D2B201FC4F40054F43E /* Share.swift */; }; 27 | FCBCBF9D200385B3008CC9CA /* ButtonText.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCBCBF9C200385B3008CC9CA /* ButtonText.swift */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 035AF2A01F0585FB003CD85B /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MainViewController.swift; path = "Sketch Cache Cleaner/Controllers/MainViewController.swift"; sourceTree = SOURCE_ROOT; }; 32 | 038FCAE81F058A2100755E96 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 33 | CE109E5C1F05A01400C4BF25 /* SanFranciscoDisplay-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SanFranciscoDisplay-Semibold.otf"; sourceTree = ""; }; 34 | CE25F7D31E490FA00049CF23 /* Sketch Cache Cleaner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Sketch Cache Cleaner.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | CE25F7D61E490FA00049CF23 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 36 | CE25F7DA1E490FA00049CF23 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 37 | CE25F7DF1E490FA00049CF23 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | CE25F7EA1E4914340049CF23 /* calculate_cache_size.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = calculate_cache_size.sh; sourceTree = ""; }; 39 | CE25F7EC1E49145A0049CF23 /* clear_cache.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = clear_cache.sh; sourceTree = ""; }; 40 | CE25F7EF1E4915190049CF23 /* Sketch Cache Cleaner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Sketch Cache Cleaner-Bridging-Header.h"; sourceTree = ""; }; 41 | CE25F7F01E4915190049CF23 /* STPrivilegedTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPrivilegedTask.m; sourceTree = ""; }; 42 | CE25F7F11E4915190049CF23 /* STPrivilegedTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPrivilegedTask.h; sourceTree = ""; }; 43 | CE25F7F31E491BE30049CF23 /* stop_cache.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = stop_cache.sh; sourceTree = ""; }; 44 | CEA190B01F02FE3B00C9F30A /* Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; 45 | FC4D46CC1FE92BE10012B681 /* NSFont+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSFont+Extensions.swift"; sourceTree = ""; }; 46 | FC4D46CE1FE92C770012B681 /* NSView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSView+Extensions.swift"; sourceTree = ""; }; 47 | FC4D46D01FE92C940012B681 /* NSButton+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSButton+Extensions.swift"; sourceTree = ""; }; 48 | FC4D46D21FE92CBA0012B681 /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; 49 | FC4D46D51FE92E7B0012B681 /* MainWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindow.swift; sourceTree = ""; }; 50 | FC81FE03206A80CB00BA1282 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; 51 | FCB22D2B201FC4F40054F43E /* Share.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Share.swift; sourceTree = ""; }; 52 | FCBCBF9C200385B3008CC9CA /* ButtonText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonText.swift; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | CE25F7D01E490FA00049CF23 /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 038FCAEA1F058A5800755E96 /* Storyboards & Xibs */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 038FCAE81F058A2100755E96 /* Main.storyboard */, 70 | ); 71 | name = "Storyboards & Xibs"; 72 | sourceTree = ""; 73 | }; 74 | CE25F7CA1E490FA00049CF23 = { 75 | isa = PBXGroup; 76 | children = ( 77 | CE25F7D51E490FA00049CF23 /* Sketch Cache Cleaner */, 78 | CE25F7D41E490FA00049CF23 /* Products */, 79 | ); 80 | sourceTree = ""; 81 | }; 82 | CE25F7D41E490FA00049CF23 /* Products */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | CE25F7D31E490FA00049CF23 /* Sketch Cache Cleaner.app */, 86 | ); 87 | name = Products; 88 | sourceTree = ""; 89 | }; 90 | CE25F7D51E490FA00049CF23 /* Sketch Cache Cleaner */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | CE25F7DA1E490FA00049CF23 /* Assets.xcassets */, 94 | CEE6384A1F78279F00C908C5 /* Controllers */, 95 | CE91327A1EA50C1A007F1ADD /* Extensions */, 96 | CE25F7E91E4913EE0049CF23 /* Scripts */, 97 | 038FCAEA1F058A5800755E96 /* Storyboards & Xibs */, 98 | CE25F7EE1E4914930049CF23 /* Supporting Files */, 99 | CE25F7E71E490FDB0049CF23 /* Utils */, 100 | FC4D46D41FE92CE00012B681 /* Views */, 101 | ); 102 | path = "Sketch Cache Cleaner"; 103 | sourceTree = ""; 104 | }; 105 | CE25F7E71E490FDB0049CF23 /* Utils */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | FCBCBF9C200385B3008CC9CA /* ButtonText.swift */, 109 | FC81FE03206A80CB00BA1282 /* Colors.swift */, 110 | CEA190B01F02FE3B00C9F30A /* Environment.swift */, 111 | FCB22D2B201FC4F40054F43E /* Share.swift */, 112 | CE25F7EF1E4915190049CF23 /* Sketch Cache Cleaner-Bridging-Header.h */, 113 | CE25F7F11E4915190049CF23 /* STPrivilegedTask.h */, 114 | CE25F7F01E4915190049CF23 /* STPrivilegedTask.m */, 115 | ); 116 | path = Utils; 117 | sourceTree = ""; 118 | }; 119 | CE25F7E91E4913EE0049CF23 /* Scripts */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | CE25F7EA1E4914340049CF23 /* calculate_cache_size.sh */, 123 | CE25F7EC1E49145A0049CF23 /* clear_cache.sh */, 124 | CE25F7F31E491BE30049CF23 /* stop_cache.sh */, 125 | ); 126 | path = Scripts; 127 | sourceTree = ""; 128 | }; 129 | CE25F7EE1E4914930049CF23 /* Supporting Files */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | CE109E5C1F05A01400C4BF25 /* SanFranciscoDisplay-Semibold.otf */, 133 | CE25F7DF1E490FA00049CF23 /* Info.plist */, 134 | CE25F7D61E490FA00049CF23 /* AppDelegate.swift */, 135 | ); 136 | name = "Supporting Files"; 137 | sourceTree = ""; 138 | }; 139 | CE91327A1EA50C1A007F1ADD /* Extensions */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | FC4D46D01FE92C940012B681 /* NSButton+Extensions.swift */, 143 | FC4D46CE1FE92C770012B681 /* NSView+Extensions.swift */, 144 | FC4D46D21FE92CBA0012B681 /* String+Extensions.swift */, 145 | FC4D46CC1FE92BE10012B681 /* NSFont+Extensions.swift */, 146 | ); 147 | path = Extensions; 148 | sourceTree = ""; 149 | }; 150 | CEE6384A1F78279F00C908C5 /* Controllers */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 035AF2A01F0585FB003CD85B /* MainViewController.swift */, 154 | ); 155 | path = Controllers; 156 | sourceTree = ""; 157 | }; 158 | FC4D46D41FE92CE00012B681 /* Views */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | FC4D46D51FE92E7B0012B681 /* MainWindow.swift */, 162 | ); 163 | path = Views; 164 | sourceTree = ""; 165 | }; 166 | /* End PBXGroup section */ 167 | 168 | /* Begin PBXNativeTarget section */ 169 | CE25F7D21E490FA00049CF23 /* Sketch Cache Cleaner */ = { 170 | isa = PBXNativeTarget; 171 | buildConfigurationList = CE25F7E21E490FA00049CF23 /* Build configuration list for PBXNativeTarget "Sketch Cache Cleaner" */; 172 | buildPhases = ( 173 | CE25F7CF1E490FA00049CF23 /* Sources */, 174 | CE25F7D01E490FA00049CF23 /* Frameworks */, 175 | CE25F7D11E490FA00049CF23 /* Resources */, 176 | FCB22D27201FC2570054F43E /* SwiftLint */, 177 | ); 178 | buildRules = ( 179 | ); 180 | dependencies = ( 181 | ); 182 | name = "Sketch Cache Cleaner"; 183 | packageProductDependencies = ( 184 | ); 185 | productName = "Sketch Cache Cleaner"; 186 | productReference = CE25F7D31E490FA00049CF23 /* Sketch Cache Cleaner.app */; 187 | productType = "com.apple.product-type.application"; 188 | }; 189 | /* End PBXNativeTarget section */ 190 | 191 | /* Begin PBXProject section */ 192 | CE25F7CB1E490FA00049CF23 /* Project object */ = { 193 | isa = PBXProject; 194 | attributes = { 195 | LastSwiftUpdateCheck = 0820; 196 | LastUpgradeCheck = 1220; 197 | ORGANIZATIONNAME = "Sasha Prokhorenko"; 198 | TargetAttributes = { 199 | CE25F7D21E490FA00049CF23 = { 200 | CreatedOnToolsVersion = 8.2.1; 201 | DevelopmentTeam = GW82A8W73Z; 202 | LastSwiftMigration = 1020; 203 | ProvisioningStyle = Automatic; 204 | }; 205 | }; 206 | }; 207 | buildConfigurationList = CE25F7CE1E490FA00049CF23 /* Build configuration list for PBXProject "Sketch Cache Cleaner" */; 208 | compatibilityVersion = "Xcode 12.0"; 209 | developmentRegion = en; 210 | hasScannedForEncodings = 0; 211 | knownRegions = ( 212 | en, 213 | Base, 214 | ); 215 | mainGroup = CE25F7CA1E490FA00049CF23; 216 | packageReferences = ( 217 | ); 218 | productRefGroup = CE25F7D41E490FA00049CF23 /* Products */; 219 | projectDirPath = ""; 220 | projectRoot = ""; 221 | targets = ( 222 | CE25F7D21E490FA00049CF23 /* Sketch Cache Cleaner */, 223 | ); 224 | }; 225 | /* End PBXProject section */ 226 | 227 | /* Begin PBXResourcesBuildPhase section */ 228 | CE25F7D11E490FA00049CF23 /* Resources */ = { 229 | isa = PBXResourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | CE109E5D1F05A01400C4BF25 /* SanFranciscoDisplay-Semibold.otf in Resources */, 233 | CE25F7DB1E490FA00049CF23 /* Assets.xcassets in Resources */, 234 | 038FCAE91F058A2100755E96 /* Main.storyboard in Resources */, 235 | CE25F7ED1E49145A0049CF23 /* clear_cache.sh in Resources */, 236 | CE25F7EB1E4914340049CF23 /* calculate_cache_size.sh in Resources */, 237 | CE25F7F41E491BE30049CF23 /* stop_cache.sh in Resources */, 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | }; 241 | /* End PBXResourcesBuildPhase section */ 242 | 243 | /* Begin PBXShellScriptBuildPhase section */ 244 | FCB22D27201FC2570054F43E /* SwiftLint */ = { 245 | isa = PBXShellScriptBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | ); 249 | inputPaths = ( 250 | ); 251 | name = SwiftLint; 252 | outputPaths = ( 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | shellPath = /bin/sh; 256 | shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 257 | }; 258 | /* End PBXShellScriptBuildPhase section */ 259 | 260 | /* Begin PBXSourcesBuildPhase section */ 261 | CE25F7CF1E490FA00049CF23 /* Sources */ = { 262 | isa = PBXSourcesBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | FC4D46D11FE92C940012B681 /* NSButton+Extensions.swift in Sources */, 266 | FC4D46D61FE92E7B0012B681 /* MainWindow.swift in Sources */, 267 | FCB22D2C201FC4F40054F43E /* Share.swift in Sources */, 268 | 035AF2A11F0585FB003CD85B /* MainViewController.swift in Sources */, 269 | CEA190B11F02FE3B00C9F30A /* Environment.swift in Sources */, 270 | FC4D46D31FE92CBA0012B681 /* String+Extensions.swift in Sources */, 271 | FC4D46CF1FE92C770012B681 /* NSView+Extensions.swift in Sources */, 272 | FCBCBF9D200385B3008CC9CA /* ButtonText.swift in Sources */, 273 | FC81FE04206A80CB00BA1282 /* Colors.swift in Sources */, 274 | FC4D46CD1FE92BE10012B681 /* NSFont+Extensions.swift in Sources */, 275 | CE25F7D71E490FA00049CF23 /* AppDelegate.swift in Sources */, 276 | CE25F7F21E4915190049CF23 /* STPrivilegedTask.m in Sources */, 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXSourcesBuildPhase section */ 281 | 282 | /* Begin XCBuildConfiguration section */ 283 | CE25F7E01E490FA00049CF23 /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | ALWAYS_SEARCH_USER_PATHS = NO; 287 | CLANG_ANALYZER_NONNULL = YES; 288 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 289 | CLANG_CXX_LIBRARY = "libc++"; 290 | CLANG_ENABLE_MODULES = YES; 291 | CLANG_ENABLE_OBJC_ARC = YES; 292 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 293 | CLANG_WARN_BOOL_CONVERSION = YES; 294 | CLANG_WARN_COMMA = YES; 295 | CLANG_WARN_CONSTANT_CONVERSION = YES; 296 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 297 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 298 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 299 | CLANG_WARN_EMPTY_BODY = YES; 300 | CLANG_WARN_ENUM_CONVERSION = YES; 301 | CLANG_WARN_INFINITE_RECURSION = YES; 302 | CLANG_WARN_INT_CONVERSION = YES; 303 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 304 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 305 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 307 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 308 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 309 | CLANG_WARN_STRICT_PROTOTYPES = YES; 310 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 311 | CLANG_WARN_UNREACHABLE_CODE = YES; 312 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 313 | CODE_SIGN_IDENTITY = "-"; 314 | COPY_PHASE_STRIP = NO; 315 | DEBUG_INFORMATION_FORMAT = dwarf; 316 | ENABLE_STRICT_OBJC_MSGSEND = YES; 317 | ENABLE_TESTABILITY = YES; 318 | GCC_C_LANGUAGE_STANDARD = gnu99; 319 | GCC_DYNAMIC_NO_PIC = NO; 320 | GCC_NO_COMMON_BLOCKS = YES; 321 | GCC_OPTIMIZATION_LEVEL = 0; 322 | GCC_PREPROCESSOR_DEFINITIONS = ( 323 | "DEBUG=1", 324 | "$(inherited)", 325 | ); 326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 328 | GCC_WARN_UNDECLARED_SELECTOR = YES; 329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 330 | GCC_WARN_UNUSED_FUNCTION = YES; 331 | GCC_WARN_UNUSED_VARIABLE = YES; 332 | MACOSX_DEPLOYMENT_TARGET = 10.13; 333 | MTL_ENABLE_DEBUG_INFO = YES; 334 | ONLY_ACTIVE_ARCH = YES; 335 | SDKROOT = macosx; 336 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 337 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 338 | }; 339 | name = Debug; 340 | }; 341 | CE25F7E11E490FA00049CF23 /* Release */ = { 342 | isa = XCBuildConfiguration; 343 | buildSettings = { 344 | ALWAYS_SEARCH_USER_PATHS = NO; 345 | CLANG_ANALYZER_NONNULL = YES; 346 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 347 | CLANG_CXX_LIBRARY = "libc++"; 348 | CLANG_ENABLE_MODULES = YES; 349 | CLANG_ENABLE_OBJC_ARC = YES; 350 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 351 | CLANG_WARN_BOOL_CONVERSION = YES; 352 | CLANG_WARN_COMMA = YES; 353 | CLANG_WARN_CONSTANT_CONVERSION = YES; 354 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 355 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 356 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 357 | CLANG_WARN_EMPTY_BODY = YES; 358 | CLANG_WARN_ENUM_CONVERSION = YES; 359 | CLANG_WARN_INFINITE_RECURSION = YES; 360 | CLANG_WARN_INT_CONVERSION = YES; 361 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 362 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 363 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 364 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 365 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 366 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 367 | CLANG_WARN_STRICT_PROTOTYPES = YES; 368 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 369 | CLANG_WARN_UNREACHABLE_CODE = YES; 370 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 371 | CODE_SIGN_IDENTITY = "-"; 372 | COPY_PHASE_STRIP = NO; 373 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 374 | ENABLE_NS_ASSERTIONS = NO; 375 | ENABLE_STRICT_OBJC_MSGSEND = YES; 376 | GCC_C_LANGUAGE_STANDARD = gnu99; 377 | GCC_NO_COMMON_BLOCKS = YES; 378 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 379 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 380 | GCC_WARN_UNDECLARED_SELECTOR = YES; 381 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 382 | GCC_WARN_UNUSED_FUNCTION = YES; 383 | GCC_WARN_UNUSED_VARIABLE = YES; 384 | MACOSX_DEPLOYMENT_TARGET = 10.13; 385 | MTL_ENABLE_DEBUG_INFO = NO; 386 | SDKROOT = macosx; 387 | SWIFT_COMPILATION_MODE = wholemodule; 388 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 389 | }; 390 | name = Release; 391 | }; 392 | CE25F7E31E490FA00049CF23 /* Debug */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 396 | CLANG_ENABLE_MODULES = YES; 397 | CLANG_ENABLE_OBJC_WEAK = YES; 398 | CODE_SIGN_IDENTITY = "Apple Development"; 399 | COMBINE_HIDPI_IMAGES = YES; 400 | DEVELOPMENT_TEAM = GW82A8W73Z; 401 | ENABLE_HARDENED_RUNTIME = YES; 402 | INFOPLIST_FILE = "Sketch Cache Cleaner/Info.plist"; 403 | LD_RUNPATH_SEARCH_PATHS = ( 404 | "$(inherited)", 405 | "@executable_path/../Frameworks", 406 | ); 407 | MACOSX_DEPLOYMENT_TARGET = 10.13; 408 | MARKETING_VERSION = 1.0.8b; 409 | PRODUCT_BUNDLE_IDENTIFIER = "me.minikin.Sketch-Cache-Cleaner"; 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | SWIFT_OBJC_BRIDGING_HEADER = "Sketch Cache Cleaner/Utils/Sketch Cache Cleaner-Bridging-Header.h"; 412 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 413 | SWIFT_VERSION = 5.0; 414 | }; 415 | name = Debug; 416 | }; 417 | CE25F7E41E490FA00049CF23 /* Release */ = { 418 | isa = XCBuildConfiguration; 419 | buildSettings = { 420 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 421 | CLANG_ENABLE_MODULES = YES; 422 | CLANG_ENABLE_OBJC_WEAK = YES; 423 | CODE_SIGN_IDENTITY = "Apple Development"; 424 | COMBINE_HIDPI_IMAGES = YES; 425 | DEVELOPMENT_TEAM = GW82A8W73Z; 426 | ENABLE_HARDENED_RUNTIME = YES; 427 | INFOPLIST_FILE = "Sketch Cache Cleaner/Info.plist"; 428 | LD_RUNPATH_SEARCH_PATHS = ( 429 | "$(inherited)", 430 | "@executable_path/../Frameworks", 431 | ); 432 | MACOSX_DEPLOYMENT_TARGET = 10.13; 433 | MARKETING_VERSION = 1.0.8b; 434 | PRODUCT_BUNDLE_IDENTIFIER = "me.minikin.Sketch-Cache-Cleaner"; 435 | PRODUCT_NAME = "$(TARGET_NAME)"; 436 | SWIFT_OBJC_BRIDGING_HEADER = "Sketch Cache Cleaner/Utils/Sketch Cache Cleaner-Bridging-Header.h"; 437 | SWIFT_VERSION = 5.0; 438 | }; 439 | name = Release; 440 | }; 441 | /* End XCBuildConfiguration section */ 442 | 443 | /* Begin XCConfigurationList section */ 444 | CE25F7CE1E490FA00049CF23 /* Build configuration list for PBXProject "Sketch Cache Cleaner" */ = { 445 | isa = XCConfigurationList; 446 | buildConfigurations = ( 447 | CE25F7E01E490FA00049CF23 /* Debug */, 448 | CE25F7E11E490FA00049CF23 /* Release */, 449 | ); 450 | defaultConfigurationIsVisible = 0; 451 | defaultConfigurationName = Release; 452 | }; 453 | CE25F7E21E490FA00049CF23 /* Build configuration list for PBXNativeTarget "Sketch Cache Cleaner" */ = { 454 | isa = XCConfigurationList; 455 | buildConfigurations = ( 456 | CE25F7E31E490FA00049CF23 /* Debug */, 457 | CE25F7E41E490FA00049CF23 /* Release */, 458 | ); 459 | defaultConfigurationIsVisible = 0; 460 | defaultConfigurationName = Release; 461 | }; 462 | /* End XCConfigurationList section */ 463 | }; 464 | rootObject = CE25F7CB1E490FA00049CF23 /* Project object */; 465 | } 466 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 2/6/17. 6 | // Copyright © 2017 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | func applicationDidFinishLaunching(_: Notification) {} 14 | } 15 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "bg.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/bg.imageset/bg.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/bg.imageset/bg.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/boxWithSketch.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "boxWithSketch.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/boxWithSketch.imageset/boxWithSketch.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/boxWithSketch.imageset/boxWithSketch.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/cleared.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "cleared.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/cleared.imageset/cleared.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/cleared.imageset/cleared.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/closedBox.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "closedBox.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/closedBox.imageset/closedBox.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/closedBox.imageset/closedBox.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/facebookButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "facebookButton.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/facebookButton.imageset/facebookButton.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/facebookButton.imageset/facebookButton.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/loader.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "loader.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/loader.imageset/loader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/loader.imageset/loader.png -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/note.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "note.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/note.imageset/note.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/note.imageset/note.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/openBox.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "openBox.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/openBox.imageset/openBox.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/openBox.imageset/openBox.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/start.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "start2.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/start.imageset/start2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/start.imageset/start2.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/tweeterButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "tweeterButton.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Assets.xcassets/tweeterButton.imageset/tweeterButton.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/Assets.xcassets/tweeterButton.imageset/tweeterButton.pdf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Controllers/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 2/6/17. 6 | // Copyright © 2017 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | final class MainViewController: NSViewController { 12 | // MARK: - IBOutlets 13 | 14 | @IBOutlet private var backgroundView: NSView! 15 | @IBOutlet private var button: NSButton! 16 | @IBOutlet private var shareToTweeterButton: NSButton! 17 | @IBOutlet private var shareToFaceBookButton: NSButton! 18 | @IBOutlet private var mainImage: NSImageView! 19 | @IBOutlet private var backgroundImage: NSImageView! 20 | @IBOutlet private var cacheCleared: NSImageView! 21 | @IBOutlet private var notificationLabel: NSTextField! 22 | @IBOutlet private var sketchLabel: NSTextField! 23 | @IBOutlet private var progress: NSProgressIndicator! 24 | 25 | // MARK: - Instance Properties 26 | 27 | private var permissionGranted = false 28 | private var stringToTest = "" 29 | private let privilegedTask = STPrivilegedTask() 30 | private let bashPath = Environment.bashPath 31 | private let calculateCacheSizeTask = [Environment.calculateCacheScriptPath] 32 | private let clearCacheTask = [Environment.clearCacheScriptPath] 33 | 34 | // MARK: - ViewController lifecycle 35 | 36 | override func viewDidLoad() { 37 | super.viewDidLoad() 38 | configureInitialVCState() 39 | } 40 | 41 | override func viewWillAppear() { 42 | super.viewWillAppear() 43 | additionalVCConfigure() 44 | } 45 | 46 | // MARK: - Initial state 47 | 48 | private func configureInitialVCState() { 49 | backgroundImage.isHidden = true 50 | cacheCleared.isHidden = true 51 | notificationLabel.isHidden = true 52 | shareToTweeterButton.isHidden = true 53 | shareToFaceBookButton.isHidden = true 54 | } 55 | 56 | private func additionalVCConfigure() { 57 | view.window?.titlebarAppearsTransparent = true 58 | view.window?.backgroundColor = Colors.background 59 | view.window?.contentView?.setFrameSize(CGSize(width: (view.window?.contentView?.frame.width)!, 60 | height: (view.window?.contentView?.frame.height)! + 20)) 61 | NSButton.setButton(button, title: ButtonText.enableAndScan) 62 | } 63 | 64 | private func appState() { 65 | switch (permissionGranted, button.title) { 66 | case (false, ButtonText.enableAndScan): 67 | button.title = ButtonText.enableAndScan 68 | askPermission() 69 | case (true, ButtonText.scanning): 70 | checkSizeOfCache() 71 | case (true, stringToTest): 72 | clearCache() 73 | default: 74 | break 75 | } 76 | } 77 | 78 | // MARK: - Helpers 79 | 80 | private func askPermission() { 81 | privilegedTask.launchPath = bashPath 82 | privilegedTask.arguments = calculateCacheSizeTask 83 | privilegedTask.currentDirectoryPath = Bundle.main.resourcePath 84 | let err = privilegedTask.launch() 85 | if err != errAuthorizationSuccess { 86 | if err == errAuthorizationCanceled { 87 | permissionGranted = false 88 | return 89 | } else { 90 | print("Something went wrong:", err) 91 | // For error codes, see http://www.opensource.apple.com/source/libsecurity_authorization/libsecurity_authorization-36329/lib/Authorization.h 92 | } 93 | } 94 | privilegedTask.waitUntilExit() 95 | permissionGranted = true 96 | backgroundImage.isHidden = false 97 | progress.startAnimation(self) 98 | button.isEnabled = false 99 | NSButton.setButton(button, title: ButtonText.scanning) 100 | mainImage.cell?.image = #imageLiteral(resourceName: "closedBox") 101 | DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { 102 | self.button.isEnabled = true 103 | self.checkSizeOfCache() 104 | } 105 | } 106 | 107 | private func checkSizeOfCache() { 108 | progress.stopAnimation(self) 109 | let readHandle = privilegedTask.outputFileHandle 110 | let outputData = readHandle?.readDataToEndOfFile() 111 | let outputString = String(data: outputData!, encoding: .utf8) 112 | let stringArray = outputString?.components(separatedBy: "/") 113 | guard let stringToDispaly = stringArray?[0] else { return } 114 | if stringToDispaly.trim() == "0B" || stringToDispaly == "" { 115 | finalUIState() 116 | } else { 117 | stringToTest = "Clear \(stringToDispaly.trim())B" 118 | NSButton.setButton(button, title: "Clear \(stringToDispaly.trim())B") 119 | mainImage.cell?.image = #imageLiteral(resourceName: "boxWithSketch") 120 | notificationLabel.isHidden = false 121 | } 122 | } 123 | 124 | private func clearCache() { 125 | privilegedTask.launchPath = bashPath 126 | privilegedTask.arguments = clearCacheTask 127 | privilegedTask.currentDirectoryPath = Bundle.main.resourcePath 128 | let err = privilegedTask.launch() 129 | if err != errAuthorizationSuccess { 130 | if err == errAuthorizationCanceled { 131 | print("User cancelled", permissionGranted) 132 | return 133 | } else { 134 | print("Something went wrong:", err) 135 | } 136 | } 137 | privilegedTask.waitUntilExit() 138 | finalUIState() 139 | } 140 | 141 | private func finalUIState() { 142 | mainImage.cell?.image = #imageLiteral(resourceName: "openBox") 143 | button.isHidden = true 144 | cacheCleared.isHidden = false 145 | notificationLabel.isHidden = true 146 | shareToTweeterButton.isHidden = false 147 | shareToFaceBookButton.isHidden = false 148 | } 149 | 150 | // MARK: - Actions 151 | 152 | @IBAction private func buttonPressed(_: NSButton) { 153 | appState() 154 | } 155 | 156 | @IBAction private func shareToTweeterDidPress(_: NSButton) { 157 | NSWorkspace.shared.open(Share.twitterMessage(stringToTest)) 158 | } 159 | 160 | @IBAction private func shareToFacebookrDidPress(_: NSButton) { 161 | NSWorkspace.shared.open(Share.facebookMessage(stringToTest)) 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Extensions/NSButton+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSButtonExtensions.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 19.12.17. 6 | // Copyright © 2017 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | extension NSButton { 12 | @discardableResult 13 | static func setButton(_ button: NSButton, title: String) -> NSButton { 14 | button.title = title 15 | button.backgroundColor = NSColor(red: 1.0, green: 0.70, blue: 0.0, alpha: 1.00) 16 | let textColor = NSColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.00) 17 | let style = NSMutableParagraphStyle() 18 | style.alignment = .center 19 | 20 | let font = NSFont.mainFont(ofSize: 14) 21 | let attributes = [NSAttributedString.Key.foregroundColor: textColor, 22 | NSAttributedString.Key.font: font, 23 | NSAttributedString.Key.paragraphStyle: style] as [NSAttributedString.Key: Any] 24 | button.attributedTitle = NSAttributedString(string: title, attributes: attributes) 25 | button.layer?.cornerRadius = 3.0 26 | button.layer?.masksToBounds = true 27 | return button 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Extensions/NSFont+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSFontExtensions.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 19.12.17. 6 | // Copyright © 2017 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | extension NSFont { 12 | private static func customFont(name: String, size: CGFloat) -> NSFont { 13 | let font = NSFont(name: name, size: size) 14 | assert(font != nil, "Can't load font: \(name)") 15 | return font ?? NSFont.systemFont(ofSize: size) 16 | } 17 | 18 | /// Main font 19 | static func mainFont(ofSize size: CGFloat) -> NSFont { 20 | customFont(name: "San Francisco Display Semibold", size: size) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Extensions/NSView+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSViewExtensions.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 19.12.17. 6 | // Copyright © 2017 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | extension NSView { 12 | var backgroundColor: NSColor? { 13 | get { 14 | guard let colorRef = layer?.backgroundColor else { return nil } 15 | return NSColor(cgColor: colorRef) 16 | } 17 | set { 18 | wantsLayer = true 19 | layer?.backgroundColor = newValue?.cgColor 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Extensions/String+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringExtensions.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 19.12.17. 6 | // Copyright © 2017 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | func trim() -> String { 13 | trimmingCharacters(in: CharacterSet.whitespaces) 14 | } 15 | 16 | func urlEncode() -> String { 17 | addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "none" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ATSApplicationFontsPath 6 | SanFranciscoDisplay-Semibold.otf 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(MARKETING_VERSION) 23 | CFBundleVersion 24 | 1 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | NSHumanReadableCopyright 30 | Copyright © 2017 Sasha Prokhorenko. All rights reserved. 31 | NSMainStoryboardFile 32 | Main 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/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 | 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 | 204 | 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 | YnBsaXN0MDDUAQIDBAUGTE1YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK8QEQcI 272 | ERYbHCgpKi41Njs+QUZJVSRudWxs1AkKCwwNDg8QViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05T 273 | Q29sb3KAEBIAwAAAgAKADtISCRMVWk5TLm9iamVjdHOhFIADgA3SEgkXGqIYGYAEgAWADBAA1x0JHh8g 274 | ISIjJCUmGxsnVk5TU2l6ZVlOU1BERkRhdGFfEBBOU0NvbG9yU3BhY2VOYW1lXxAZTlNJbnRlcm5hbExh 275 | eW91dERpcmVjdGlvbl8QD05TQml0c1BlclNhbXBsZVxOU0NvbG9yU3BhY2WABoALgAqAB4AIWXsxOTIs 276 | IDE2fV8QGU5TQ2FsaWJyYXRlZFJHQkNvbG9yU3BhY2XSKwksLVROU0lEEAGACdIvMDEyWiRjbGFzc25h 277 | bWVYJGNsYXNzZXNcTlNDb2xvclNwYWNlojM0XE5TQ29sb3JTcGFjZVhOU09iamVjdE8RPmMlUERGLTEu 278 | MwolxOXy5eun86DQxMYKNCAwIG9iago8PCAvTGVuZ3RoIDUgMCBSIC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl 279 | ID4+CnN0cmVhbQp4AY1SwU7DMAy95ysetw6pWeykaXtl4sINUWlCiMMUNm2iBW2D/8fu0k2AkFDTuo6f 280 | X/Js73GPPcoqoOQa3jkEeQ9rLPGG+eJISEfQ+BwTnI3YCZ7g5CkJHEARacBNZ0pnXRvRJVDIcbHWO+LY 281 | ViCPbsC8S8rWbfCE4vF9hjI6FJ/ZHtSSKZD9h2xfxVaEYp39D/VbFCn722ynvEX2VzMjfL9xE8+E3yle 282 | cMcfPBN/P8bN+fxVxut99R4T30vOv5rhGd0dbjsprxa4AWMAkfXkaymbkRIFG5vILWu5GoxVOwMuPxoT 283 | QPoGl5wLlebyJXym5fHUhC2W19LMP3p8aql0mqXT5tzp0kMWsy6Zhk1WIc0e4GUK5MeB2Gqn9QJu3NWI 284 | +g7J5KAAM37UKJmadPpE1SbjI1esVUDmbtCjQiuwXvZrG0wvelWy7pxS3RjTnF4F/lOfjGNoA1WuMs42 285 | HNkHGWVL3DZ17SETXla6OOo66f4CldKfmQplbmRzdHJlYW0KZW5kb2JqCjUgMCBvYmoKMzc0CmVuZG9i 286 | agoyIDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMyAwIFIgL1Jlc291cmNlcyA2IDAgUiAvQ29u 287 | dGVudHMgNCAwIFIgL01lZGlhQm94IFswIDAgMTkyIDE2XQo+PgplbmRvYmoKNiAwIG9iago8PCAvUHJv 288 | Y1NldCBbIC9QREYgL1RleHQgXSAvQ29sb3JTcGFjZSA8PCAvQ3MxIDcgMCBSIC9DczIgOSAwIFIgPj4g 289 | L0ZvbnQgPDwKL1RjMSA4IDAgUiA+PiA+PgplbmRvYmoKMTAgMCBvYmoKPDwgL0xlbmd0aCAxMSAwIFIg 290 | L04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB 291 | hVVbiBtVGP6TOckKu87T2tUtpEO9dCm7S7YV3aW0mluTtGsastnVFkGzk5NkzOwkzkzSC30qguKLq75J 292 | Qby9LQiC0nrB1gf7UqlQVnfrIig+tHhBKPRFt/E7k2QmWWqbZc988/3f+W/nnxmigbVCva77FaIlwzZz 293 | yajy3NFjysA6+ekhGqRRGiyoVj2Szc4SfkIrrv2/Wz+QTzBXJ+5s71dvuRsscksl8t0Hvla01CXgE0SB 294 | s2rdtIkGhsFPH7frAoschk0kCPyiwOU2ho2GF9v4NUeTz8WgOQssq5VCEXgFeHyxhy/34HYOUMBPkhvc 295 | 1FRF9CJr1kqazh1De7mHuUd5N7ikN1Cz89uBdciqzh3GdQy1v1IsxAWeBF5RC4k54EeArzW1hUwH367b 296 | 0RzwY0T+nY3qfAR4N3CqZB6cB4Yfv1lppLr4nVOV/LPgt4H/xljMHOnsXVOtGHpJO8HfrvC06G+ISFI0 297 | O50Hhh/pgFnLCT1ykEpFHk8AjwO/Xq0dFjnAp/SZ1ZwTvMhn7VQlJvIU/OWXCoeywKPAv3I9KfSIJf1b 298 | t7OdHFjI0DMiLmKxOLeceuGHhexKPgUecZlum/nOXrZc0g6mO/pPKmZK8GLvtbruzChyC/jNRk7UjliB 299 | yYKZSALDZyDLjXnRT4GbtOArEKcaLWJVyaBNUihHSYriWicTlhJppIPhsHIwHHddzYSzz6IqeI2ajs3C 300 | mnWU7Z1drUJlsAZdd7QqxUIfUQOeKvQH2IrrU6EY7hrgyv/jp53LjY6fGhthYbYX//vYLNvPptkMKewp 301 | 9jQ7wOJgZ9g+13cWe7oViXxuIErbz8uIyB3dAmq/iBptKmD9BYoaWa6Hvq4sjzbGPMsZ8wVNvfLG3z29 302 | 0rCz6iom+jp65F49D/wWuB5Yxboe2HB9KIGfAhv4W0dvvFpqnr3TZXFSGk601qfbehZdVQSV6s7OJXRB 303 | Q828p+aJXh+XTn/5oBdtlZ17/urQpdMlY3nUY0UX+KuZWxk6M+6x4R/Df4ZXw++FPwz/Lr0tfSp9JZ2X 304 | PpcukyJdkC5KX0vfSh9LX7j6u82Qe/YkMhdzJfIW09WtsLfXmFg5Km+XH5bj8g75UXnWVSnyiDwlp+Rd 305 | sGx3z82bb6W3cvTlKKJ1+3PnWOJZ0VxPOAPf/ZgAzYvYNwPzyFij4/Bpot9i3gw6CW3vk9epiIXYFEtv 306 | me5pMfNd38FEMB6MkBLcHZwJTgUPCdx9loO7YJvBmujNDfPhKvoq5TY/Ib4nFKvVT5pauWIre8LhJ5UI 307 | Pn1cSRvq5LhS0HXFMVmKyS1uNnlxksR3U+wjuplzvoe+bVc8zn6GaP9fePd973HHGkQrFtHI4x43hnfl 308 | A+8SnXtCbZjNtj/y+b4jskp79zj3vqEo3l8/t1o38R4beIto881W65/3W63ND+B/g+iC/h+gn3xVCmVu 309 | ZHN0cmVhbQplbmRvYmoKMTEgMCBvYmoKMTA3OQplbmRvYmoKNyAwIG9iagpbIC9JQ0NCYXNlZCAxMCAw 310 | IFIgXQplbmRvYmoKMTIgMCBvYmoKPDwgL0xlbmd0aCAxMyAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZp 311 | Y2VSR0IgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngBnZZ3VFPZFofPvTe90BIiICX0GnoJ 312 | INI7SBUEUYlJgFAChoQmdkQFRhQRKVZkVMABR4ciY0UUC4OCYtcJ8hBQxsFRREXl3YxrCe+tNfPemv3H 313 | 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 355 | Jm1m5t/3hPP7CmVuZHN0cmVhbQplbmRvYmoKMTMgMCBvYmoKMjYxMgplbmRvYmoKOSAwIG9iagpbIC9J 356 | Q0NCYXNlZCAxMiAwIFIgXQplbmRvYmoKMyAwIG9iago8PCAvVHlwZSAvUGFnZXMgL01lZGlhQm94IFsw 357 | IDAgMTkyIDE2XSAvQ291bnQgMSAvS2lkcyBbIDIgMCBSIF0gPj4KZW5kb2JqCjE0IDAgb2JqCjw8IC9U 358 | eXBlIC9DYXRhbG9nIC9QYWdlcyAzIDAgUiA+PgplbmRvYmoKOCAwIG9iago8PCAvVHlwZSAvRm9udCAv 359 | U3VidHlwZSAvVHlwZTEgL0Jhc2VGb250IC9CWlZNQk4rU2FuRnJhbmNpc2NvRGlzcGxheS1TZW1pYm9s 360 | ZAovRm9udERlc2NyaXB0b3IgMTUgMCBSIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNvZGluZyAvRmlyc3RD 361 | aGFyIDMyIC9MYXN0Q2hhcgoxMTcgL1dpZHRocyBbIDE5OCAyNjYgMCAwIDAgMCAwIDAgMCAwIDAgMCAw 362 | IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwCjAgMCAwIDAgMCAwIDAgNjIwIDAgMCAwIDAgMCAw 363 | IDAgMCAwIDAgMCAwIDAgMCAwIDU4MiAwIDAgMCAwIDAgNTUzIDAgMCAwIDAKMCAwIDAgNTI4IDAgNTIw 364 | IDU4MyA1MzkgMCAwIDU3OCAyNTkgMCA1MTEgMjU2IDAgMCA1NTcgMCAwIDM2NCA0OTkgMzYxIDU3NApd 365 | ID4+CmVuZG9iagoxNSAwIG9iago8PCAvVHlwZSAvRm9udERlc2NyaXB0b3IgL0ZvbnROYW1lIC9CWlZN 366 | Qk4rU2FuRnJhbmNpc2NvRGlzcGxheS1TZW1pYm9sZCAvRmxhZ3MKMzIgL0ZvbnRCQm94IFstMjM4IC0y 367 | NTIgMTAzNiA5NTBdIC9JdGFsaWNBbmdsZSAwIC9Bc2NlbnQgOTUyIC9EZXNjZW50IC0yNDEKL0NhcEhl 368 | aWdodCA2ODAgL1N0ZW1WIDExNyAvWEhlaWdodCA1MjYgL1N0ZW1IIDk3IC9BdmdXaWR0aCA1MDEgL01h 369 | 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 523 | SI48j3e6QyJbyNvdIYNBPl+Tizc0LWwHWVSmQUywidPovChmErTMMJcWf67qjYkkKX9EQFiphfsskFqT 524 | RWWG5OvjIJheHaAjIfG6GEcvmgNh0g50FQxxVFiHU2uqOBQLs8PHjXpv3mQJO/AzVx6c+aWVdtn3Z5hN 525 | 2fUGG4ZGtibKRYoUfKfZBAw8ZDvyJ+xzqOQUFT0Qkm9HJs9uW6A1oarf0ZUHrvjbNenoKSTiBTkukD+i 526 | qYdqZlz00oyVg76vL+uTVYuWjwyUrlYZ2tBj64lyDhQsSl3IUesqUZinRqlBmKMEqXE0Y/EGHSSzVMKj 527 | j3aQcq6BT7mNZDacIUCA3eqreNAKvMpGQigb0ctqe4FwObFBwkvnADMEpUKpgFy1QolQXkCB8z65DJ5S 528 | rGXBBmGuhHu1Nc7ALX44jzBKO5gg7DCI1dXfXk2sFmKqE69+W26IiU5MpMLKaLq6erL66rdJ1dF0J0bL 529 | 3CdDBL9L0+EoBITSzKCIe0TTJg1vMUf31qnDGLTi1inDmFBqiBaoa5L2qKKXIzqGx+WEF2nmO2rGYjf7 530 | enTQnpYYhOwFr6otqK7plEWQsTmXMWtiRmdrwSABmkrbIa4VGTr60xe/hMcq/TBx/jNNN6VQHoJRklhj 531 | ZZiv2Hlxv0HEAbz4XyZPVB0KZW5kc3RyZWFtCmVuZG9iagoxNyAwIG9iago5NjIyCmVuZG9iagoxOCAw 532 | IG9iagooTWFjIE9TIFggMTAuMTIuNCBRdWFydHogUERGQ29udGV4dCkKZW5kb2JqCjE5IDAgb2JqCihE 533 | OjIwMTcwNTAxMTMyMTM4WjAwJzAwJykKZW5kb2JqCjEgMCBvYmoKPDwgL1Byb2R1Y2VyIDE4IDAgUiAv 534 | Q3JlYXRpb25EYXRlIDE5IDAgUiAvTW9kRGF0ZSAxOSAwIFIgPj4KZW5kb2JqCnhyZWYKMCAyMAowMDAw 535 | MDAwMDAwIDY1NTM1IGYgCjAwMDAwMTUzMzggMDAwMDAgbiAKMDAwMDAwMDQ4OSAwMDAwMCBuIAowMDAw 536 | MDA0NzExIDAwMDAwIG4gCjAwMDAwMDAwMjIgMDAwMDAgbiAKMDAwMDAwMDQ3MCAwMDAwMCBuIAowMDAw 537 | MDAwNTkyIDAwMDAwIG4gCjAwMDAwMDE5MDMgMDAwMDAgbiAKMDAwMDAwNDg0MyAwMDAwMCBuIAowMDAw 538 | MDA0Njc1IDAwMDAwIG4gCjAwMDAwMDA3MDAgMDAwMDAgbiAKMDAwMDAwMTg4MiAwMDAwMCBuIAowMDAw 539 | MDAxOTM5IDAwMDAwIG4gCjAwMDAwMDQ2NTQgMDAwMDAgbiAKMDAwMDAwNDc5MyAwMDAwMCBuIAowMDAw 540 | MDA1MjM4IDAwMDAwIG4gCjAwMDAwMDU1MDcgMDAwMDAgbiAKMDAwMDAxNTIyMiAwMDAwMCBuIAowMDAw 541 | MDE1MjQzIDAwMDAwIG4gCjAwMDAwMTUyOTYgMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSAyMCAvUm9v 542 | dCAxNCAwIFIgL0luZm8gMSAwIFIgL0lEIFsgPDE1ZmJhOGYyNzkzZTUxMGRlYjhmZjljNGM1YjkyY2Zl 543 | Pgo8MTVmYmE4ZjI3OTNlNTEwZGViOGZmOWM0YzViOTJjZmU+IF0gPj4Kc3RhcnR4cmVmCjE1NDEzCiUl 544 | RU9GCtIvMDc4XU5TUERGSW1hZ2VSZXCjOTo0XU5TUERGSW1hZ2VSZXBaTlNJbWFnZVJlcNIvMDw9V05T 545 | QXJyYXmiPDTSLzA/QF5OU011dGFibGVBcnJheaM/PDTTQiIJQ0RFV05TV2hpdGVEMCAwABADgA/SLzBH 546 | SFdOU0NvbG9yokc00i8wSktXTlNJbWFnZaJKNF8QD05TS2V5ZWRBcmNoaXZlctFOT1Ryb290gAEACAAR 547 | ABoAIwAtADIANwBLAFEAWgBhAG4AdQB9AH8AhACGAIgAjQCYAJoAnACeAKMApgCoAKoArACuAL0AxADO 548 | AOEA/QEPARwBHgEgASIBJAEmATABTAFRAVYBWAFaAV8BagFzAYABgwGQAZlAAEAFQBNAF0AlQDBANUA9 549 | QEBARUBUQFhAX0BnQGxAbkBwQHVAfUCAQIVAjUCQQKJApUCqAAAAAAAAAgEAAAAAAAAAUAAAAAAAAAAA 550 | AAAAAAAAQKw 551 | 552 | 553 | 554 | 555 | 556 | 557 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/SanFranciscoDisplay-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/Sketch Cache Cleaner/SanFranciscoDisplay-Semibold.otf -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Scripts/calculate_cache_size.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # calculate_cache_size.sh 4 | # Sketch Cache Cleaner 5 | # 6 | # Created by Sasha Prokhorenko on 2/6/17. 7 | # Copyright © 2017 Sasha Prokhorenko. All rights reserved. 8 | 9 | 10 | du -sh /.DocumentRevisions-V100/ 11 | 12 | exit 5 13 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Scripts/clear_cache.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # clear_cache.sh 4 | # Sketch Cache Cleaner 5 | # 6 | # Created by Sasha Prokhorenko on 2/6/17. 7 | # Copyright © 2017 Sasha Prokhorenko. All rights reserved. 8 | 9 | # that's exectly the place where sketch save versions 10 | #rm -rf /.DocumentRevisions-V100/.cs/{*,.*} 11 | 12 | # looks like we need to remove all folders 13 | rm -rf /.DocumentRevisions-V100/{*,.*} 14 | 15 | exit 5 16 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Scripts/stop_cache.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # stop_cache.sh 4 | # Sketch Cache Cleaner 5 | # 6 | # Created by Sasha Prokhorenko on 2/6/17. 7 | # Copyright © 2017 Sasha Prokhorenko. All rights reserved. 8 | 9 | # defaults write -app Sketch ApplePersistence -bool no 10 | # exit 5 11 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Utils/ButtonText.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ButtonText.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 08.01.18. 6 | // Copyright © 2018 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum ButtonText { 12 | static let enableAndScan = "Enable and Scan" 13 | static let scanning = "Scanning..." 14 | } 15 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Utils/Colors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Colors.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 27.03.18. 6 | // Copyright © 2018 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | enum Colors { 10 | static let background = NSColor(red: 0.07, green: 0.04, blue: 0.20, alpha: 1.00) 11 | } 12 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Utils/Environment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Environment.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 6/27/17. 6 | // Copyright © 2017 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum Environment { 12 | static let bashPath = "/bin/sh" 13 | static let calculateCacheScriptPath = "calculate_cache_size.sh" 14 | static let clearCacheScriptPath = "clear_cache.sh" 15 | static let webPage = "https://yo-op.github.io/sketchcachecleaner/" 16 | static let sentry = "https://90daa0afc9e04716a579a237e92d021b@sentry.io/5179181" 17 | } 18 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Utils/STPrivilegedTask.h: -------------------------------------------------------------------------------- 1 | /* 2 | # STPrivilegedTask - NSTask-like wrapper around AuthorizationExecuteWithPrivileges 3 | # Copyright (C) 2009-2016 Sveinbjorn Thordarson 4 | # 5 | # BSD License 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # * Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # * Neither the name of Sveinbjorn Thordarson nor that of any other 14 | # contributors may be used to endorse or promote products 15 | # derived from this software without specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | # DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 21 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #import 30 | 31 | #define STPrivilegedTaskDidTerminateNotification @"STPrivilegedTaskDidTerminateNotification" 32 | 33 | // Defines error value for when AuthorizationExecuteWithPrivileges no longer exists 34 | // Rather than defining a new enum, we just create a global constant 35 | extern const OSStatus errAuthorizationFnNoLongerExists; 36 | 37 | @interface STPrivilegedTask : NSObject 38 | 39 | @property (copy) NSArray *arguments; 40 | @property (copy) NSString *currentDirectoryPath; 41 | @property (copy) NSString *launchPath; 42 | 43 | @property (readonly) NSFileHandle *outputFileHandle; 44 | @property (readonly) BOOL isRunning; 45 | @property (readonly) pid_t processIdentifier; 46 | @property (readonly) int terminationStatus; 47 | 48 | @property (copy) void (^terminationHandler)(STPrivilegedTask *); 49 | 50 | - (instancetype)initWithLaunchPath:(NSString *)path; 51 | - (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args; 52 | - (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd; 53 | 54 | + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path; 55 | + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args; 56 | + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd; 57 | 58 | - (OSStatus)launch; 59 | - (void)terminate; // doesn't work 60 | - (void)waitUntilExit; 61 | 62 | @end 63 | 64 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Utils/STPrivilegedTask.m: -------------------------------------------------------------------------------- 1 | /* 2 | # STPrivilegedTask - NSTask-like wrapper around AuthorizationExecuteWithPrivileges 3 | # Copyright (C) 2009-2016 Sveinbjorn Thordarson 4 | # 5 | # BSD License 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # * Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # * Neither the name of Sveinbjorn Thordarson nor that of any other 14 | # contributors may be used to endorse or promote products 15 | # derived from this software without specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | # DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 21 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #import "STPrivilegedTask.h" 30 | 31 | #import 32 | #import 33 | #import 34 | #import 35 | #import 36 | 37 | // New error code denoting that AuthorizationExecuteWithPrivileges no longer exists 38 | OSStatus const errAuthorizationFnNoLongerExists = -70001; 39 | 40 | @implementation STPrivilegedTask 41 | { 42 | NSTimer *_checkStatusTimer; 43 | } 44 | 45 | - (instancetype)init 46 | { 47 | self = [super init]; 48 | if (self) { 49 | _launchPath = nil; 50 | _arguments = nil; 51 | _isRunning = NO; 52 | _outputFileHandle = nil; 53 | _terminationHandler = nil; 54 | _currentDirectoryPath = [[NSFileManager defaultManager] currentDirectoryPath]; 55 | } 56 | return self; 57 | } 58 | 59 | - (instancetype)initWithLaunchPath:(NSString *)path 60 | { 61 | self = [self init]; 62 | if (self) { 63 | self.launchPath = path; 64 | } 65 | return self; 66 | } 67 | 68 | - (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args 69 | { 70 | self = [self initWithLaunchPath:path]; 71 | if (self) { 72 | self.arguments = args; 73 | } 74 | return self; 75 | } 76 | 77 | - (instancetype)initWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd 78 | { 79 | self = [self initWithLaunchPath:path arguments:args]; 80 | if (self) { 81 | self.currentDirectoryPath = cwd; 82 | } 83 | return self; 84 | } 85 | 86 | #pragma mark - 87 | 88 | + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path 89 | { 90 | STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path]; 91 | #if !__has_feature(objc_arc) 92 | [task autorelease]; 93 | #endif 94 | [task launch]; 95 | [task waitUntilExit]; 96 | return task; 97 | } 98 | 99 | + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args 100 | { 101 | STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path arguments:args]; 102 | #if !__has_feature(objc_arc) 103 | [task autorelease]; 104 | #endif 105 | 106 | [task launch]; 107 | [task waitUntilExit]; 108 | return task; 109 | } 110 | 111 | + (STPrivilegedTask *)launchedPrivilegedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)args currentDirectory:(NSString *)cwd 112 | { 113 | STPrivilegedTask *task = [[STPrivilegedTask alloc] initWithLaunchPath:path arguments:args currentDirectory:cwd]; 114 | #if !__has_feature(objc_arc) 115 | [task autorelease]; 116 | #endif 117 | 118 | [task launch]; 119 | [task waitUntilExit]; 120 | return task; 121 | } 122 | 123 | # pragma mark - 124 | 125 | // return 0 for success 126 | - (OSStatus)launch 127 | { 128 | if (_isRunning) { 129 | NSLog(@"Task already running: %@", [self description]); 130 | return 0; 131 | } 132 | 133 | OSStatus err = noErr; 134 | const char *toolPath = [self.launchPath fileSystemRepresentation]; 135 | 136 | AuthorizationRef authorizationRef; 137 | AuthorizationItem myItems = { kAuthorizationRightExecute, strlen(toolPath), &toolPath, 0 }; 138 | AuthorizationRights myRights = { 1, &myItems }; 139 | AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; 140 | 141 | NSArray *arguments = self.arguments; 142 | NSUInteger numberOfArguments = [arguments count]; 143 | char *args[numberOfArguments + 1]; 144 | FILE *outputFile; 145 | 146 | // Create fn pointer to AuthorizationExecuteWithPrivileges in case it doesn't exist 147 | // in this version of MacOS 148 | static OSStatus (*_AuthExecuteWithPrivsFn)( 149 | AuthorizationRef authorization, const char *pathToTool, AuthorizationFlags options, 150 | char * const *arguments, FILE **communicationsPipe) = NULL; 151 | 152 | // Check to see if we have the correct function in our loaded libraries 153 | if (!_AuthExecuteWithPrivsFn) { 154 | // On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want 155 | // to still use it since there's no good alternative (without requiring 156 | // code signing). We'll look up the function through dyld and fail if 157 | // it is no longer accessible. If Apple removes the function entirely 158 | // this will fail gracefully. If they keep the function and throw some 159 | // sort of exception, this won't fail gracefully, but that's a risk 160 | // we'll have to take for now. 161 | // Pattern by Andy Kim from Potion Factory LLC 162 | _AuthExecuteWithPrivsFn = dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges"); 163 | if (!_AuthExecuteWithPrivsFn) { 164 | // This version of OS X has finally removed this function. Return with an error. 165 | return errAuthorizationFnNoLongerExists; 166 | } 167 | } 168 | 169 | // Use Apple's Authentication Manager APIs to get an Authorization Reference 170 | // These Apple APIs are quite possibly the most horrible of the Mac OS X APIs 171 | 172 | // create authorization reference 173 | err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef); 174 | if (err != errAuthorizationSuccess) { 175 | return err; 176 | } 177 | 178 | // pre-authorize the privileged operation 179 | err = AuthorizationCopyRights(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, flags, NULL); 180 | if (err != errAuthorizationSuccess) { 181 | return err; 182 | } 183 | 184 | // OK, at this point we have received authorization for the task. 185 | // Let's prepare to launch it 186 | 187 | // first, construct an array of c strings from NSArray w. arguments 188 | for (int i = 0; i < numberOfArguments; i++) { 189 | NSString *argString = arguments[i]; 190 | NSUInteger stringLength = [argString length]; 191 | 192 | args[i] = malloc((stringLength + 1) * sizeof(char)); 193 | snprintf(args[i], stringLength + 1, "%s", [argString fileSystemRepresentation]); 194 | } 195 | args[numberOfArguments] = NULL; 196 | 197 | // change to the current dir specified 198 | char *prevCwd = (char *)getcwd(nil, 0); 199 | chdir([self.currentDirectoryPath fileSystemRepresentation]); 200 | 201 | //use Authorization Reference to execute script with privileges 202 | err = _AuthExecuteWithPrivsFn(authorizationRef, toolPath, kAuthorizationFlagDefaults, args, &outputFile); 203 | 204 | // OK, now we're done executing, let's change back to old dir 205 | chdir(prevCwd); 206 | 207 | // free the malloc'd argument strings 208 | for (int i = 0; i < numberOfArguments; i++) { 209 | free(args[i]); 210 | } 211 | 212 | // free the auth ref 213 | AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); 214 | 215 | // we return err if execution failed 216 | if (err != errAuthorizationSuccess) { 217 | return err; 218 | } else { 219 | _isRunning = YES; 220 | } 221 | 222 | // get file handle for the command output 223 | _outputFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fileno(outputFile) closeOnDealloc:YES]; 224 | _processIdentifier = fcntl(fileno(outputFile), F_GETOWN, 0); 225 | 226 | // start monitoring task 227 | _checkStatusTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(checkTaskStatus) userInfo:nil repeats:YES]; 228 | 229 | return err; 230 | } 231 | 232 | - (void)terminate 233 | { 234 | // This doesn't work without a PID, and we can't get one. Stupid Security API 235 | // int ret = kill(pid, SIGKILL); 236 | // 237 | // if (ret != 0) { 238 | // NSLog(@"Error %d", errno); 239 | // } 240 | } 241 | 242 | // hang until task is done 243 | - (void)waitUntilExit 244 | { 245 | if (!_isRunning) { 246 | NSLog(@"Task %@ is not running", [super description]); 247 | return; 248 | } 249 | 250 | [_checkStatusTimer invalidate]; 251 | 252 | int status; 253 | pid_t pid = 0; 254 | while ((pid = waitpid(_processIdentifier, &status, WNOHANG)) == 0) { 255 | // do nothing 256 | } 257 | _terminationStatus = WEXITSTATUS(status); 258 | _isRunning = NO; 259 | } 260 | 261 | // check if task has terminated 262 | - (void)checkTaskStatus 263 | { 264 | int status; 265 | pid_t pid = waitpid(_processIdentifier, &status, WNOHANG); 266 | if (pid != 0) { 267 | _isRunning = NO; 268 | _terminationStatus = WEXITSTATUS(status); 269 | [_checkStatusTimer invalidate]; 270 | [[NSNotificationCenter defaultCenter] postNotificationName:STPrivilegedTaskDidTerminateNotification object:self]; 271 | if (_terminationHandler) { 272 | _terminationHandler(self); 273 | } 274 | } 275 | } 276 | 277 | #pragma mark - 278 | 279 | // Nice description for debugging 280 | - (NSString *)description 281 | { 282 | NSString *commandDescription = [NSString stringWithString:self.launchPath]; 283 | 284 | for (NSString *arg in self.arguments) { 285 | commandDescription = [commandDescription stringByAppendingFormat:@" '%@'", arg]; 286 | } 287 | [commandDescription stringByAppendingFormat:@" (CWD:%@)", self.currentDirectoryPath]; 288 | 289 | return [[super description] stringByAppendingFormat:@" %@", commandDescription]; 290 | } 291 | 292 | @end 293 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Utils/Share.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Share.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 29.01.18. 6 | // Copyright © 2018 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | enum Share { 10 | static func twitterMessage(_ text: String) -> URL { 11 | let tweet = "https://twitter.com/intent/tweet?text=Just%20cleared%20" 12 | + "\(text.urlEncode())%20of%20space%20on%20my%20disk%20thanks%20" 13 | + "to%20Sketch%20Cache%20Cleaner!%20Check%20it%20out:%20" 14 | + "https%3A%2F%2Fyo-op.github.io%2Fsketchcachecleaner%2F%0A" 15 | guard let url = URL(string: tweet) else { 16 | return URL(string: Environment.webPage)! 17 | } 18 | return url 19 | } 20 | 21 | static func facebookMessage(_ text: String) -> URL { 22 | let facebook = "https://www.facebook.com/dialog/share?%20app_id=1778148252492778" + 23 | "&href=https%3A%2F%2Fyo-op.github.io%2Fsketchcachecleaner%2F%0A" + 24 | ""e=Just%20cleared%20" + 25 | "\(text.urlEncode())%20of%20space%20on%20my%20disk%20thanks%20" + 26 | "to%20Sketch%20Cache%20Cleaner!%20Check%20it%20out:%20" + 27 | "&redirect_uri=https%3A%2F%2F.facebook.com" 28 | guard let url = URL(string: facebook) else { 29 | return URL(string: Environment.webPage)! 30 | } 31 | return url 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Utils/Sketch Cache Cleaner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "STPrivilegedTask.h" 6 | -------------------------------------------------------------------------------- /Sketch Cache Cleaner/Views/MainWindow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainWindow.swift 3 | // Sketch Cache Cleaner 4 | // 5 | // Created by Sasha Prokhorenko on 19.12.17. 6 | // Copyright © 2017 Sasha Prokhorenko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | final class MainWindow: NSWindow { 12 | // Keep this class 13 | } 14 | -------------------------------------------------------------------------------- /assets/RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | # Sketch Cache Cleaner 2 | 3 | ![Sketch Cache Cleaner](https://image.ibb.co/mHOoea/cleaner.png) 4 | 5 | Sketch Cache Cleaner is an app that deletes hidden Sketch history files that can take a lot of space on your hard drive and that you would probably never use. 6 | 7 | --- 8 | 9 | 1. [Warning](#warning) 10 | 2. [System Requirements](#system-requirements) 11 | 3. [Changelog](#changelog) 12 | 4. [Tips](#tips) 13 | 5. [Authors](#authors) 14 | 6. [License](#license) 15 | 16 | --- 17 | 18 | ## Warning 19 | 20 | The app idea inspired by two blog posts: [How Sketch took over 200GB of our MacBooks](https://medium.com/@thomasdegry/how-sketch-took-over-200gb-of-our-macbooks-cb7dd10c8163) & [How to recover 50 GB or even more by deleting Sketch caches files](https://medium.com/sketch-app-sources/how-to-recover-50-go-or-even-more-by-deleting-sketch-caches-files-e5829dba20e1) 21 | 22 | Please, read them in case you want to know how it works. 23 | 24 | If your **workflow** relies on **automatic versioning** by macOS 25 | (Time Machine etc.) - **DO NOT USE THIS APP!** 26 | 27 | The app will remove all files in folder: `/.DocumentRevisions-V100/` 28 | 29 | --- 30 | 31 | ## System Requirements 32 | 33 | - macOS 10.13+ 34 | - Xcode 11.4+ 35 | - Swift 5.2+ 36 | 37 | --- 38 | 39 | ## Changelog 40 | 41 | ## [1.0.7] - 2020-30-03 42 | 43 | - Add macOS Catalina support 44 | - Bump minimum macOS version to 10.13 45 | - Build with Xcode 11.4 46 | 47 | ## [1.0.6] - 2020-16-01 48 | 49 | ### Changed 50 | 51 | - Add macOS Catalina support 52 | - Build with Xcode 11 53 | 54 | ## [1.0.5] - 2019-05-02 55 | 56 | ### Changed 57 | 58 | - Migrate to Swift 5 59 | 60 | ## [1.0.4] - 2018-10-21 61 | 62 | ### Changed 63 | 64 | - Build with Xcode 10 and macOS Mojave 65 | - Migrate to Swift 4.2 66 | 67 | ## [1.0.3] - 2018-03-27 68 | 69 | ### Added 70 | 71 | - Add social sharing 72 | 73 | ### Changed 74 | 75 | - Code refactor 76 | - Build with new Xcode's build system 77 | 78 | ## [1.0.2] - 2017-09-24 79 | 80 | ### Changed 81 | 82 | - Update to Swift 4 83 | - Compiled with Xcode 9 84 | 85 | ## [1.0.1] - 2017-07-14 86 | 87 | ### Fixed 88 | 89 | - Fix compatibility issues with 10.11, 10.12beta 90 | 91 | ## [1.0.0] - 2017-07-11 92 | 93 | - Initial release 94 | 95 | --- 96 | 97 | ## Authors 98 | 99 | Idea & design: [Yuriy Oparenko](http://oparenko.com/) 100 | 101 | Development: [Sasha Prokhorenko](https://twitter.com/minikin) 102 | 103 | --- 104 | 105 | ## Tips 106 | 107 | - Use this app wisely. 108 | - Reboot your Mac after app use. 109 | 110 | --- 111 | 112 | ## License 113 | 114 | Sketch Cache Cleaner is distributed under the [MIT license](https://github.com/yo-op/sketchcachecleaner/blob/master/LICENSE.md). 115 | -------------------------------------------------------------------------------- /assets/RELEASE_NOTES.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/assets/RELEASE_NOTES.pdf -------------------------------------------------------------------------------- /assets/Sketch Cache Cleaner.md: -------------------------------------------------------------------------------- 1 | # Sketch Cache Cleaner 2 | 3 | ![Sketch Cache Cleaner](https://image.ibb.co/mHOoea/cleaner.png) 4 | 5 | Sketch Cache Cleaner is an app that deletes hidden Sketch history files that can take a lot of space on your hard drive and that you would probably never use. 6 | 7 | --- 8 | 9 | 1. [Warning](#warning) 10 | 11 | 2. [System Requirements](#system-requirements) 12 | 13 | 3. [Changelog](#changelog) 14 | 15 | 4. [Tips](#tips) 16 | 17 | 5. [Authors](#authors) 18 | 19 | 6. [License](#license) 20 | 21 | ## Warning 22 | 23 | The app idea inspired by two blog posts: [How Sketch took over 200GB of our MacBooks](https://medium.com/@thomasdegry/how-sketch-took-over-200gb-of-our-macbooks-cb7dd10c8163) & [How to recover 50 GB or even more by deleting Sketch caches files](https://medium.com/sketch-app-sources/how-to-recover-50-go-or-even-more-by-deleting-sketch-caches-files-e5829dba20e1) 24 | 25 | Please, read them in case you want to know how it works. 26 | 27 | If your **workflow** relies on **automatic versioning** by macOS 28 | 29 | (Time Machine etc.) - **DO NOT USE THIS APP!** 30 | 31 | The app will remove all files in folder: `/.DocumentRevisions-V100/` 32 | 33 | ## System Requirements 34 | 35 | - macOS 10.11+ 36 | 37 | - Xcode 10.0+ 38 | 39 | - Swift 4.2+ 40 | 41 | --- 42 | 43 | ## Changelog 44 | 45 | ## [1.0.6] - 2020-16-01 46 | 47 | ### Changed 48 | 49 | - Add macOS Catalina support 50 | - Build with Xcode 11 51 | 52 | ## Changelog 53 | 54 | ## [1.0.5] - 2019-05-02 55 | 56 | ### Changed 57 | 58 | - Migrate to Swift 5 59 | 60 | ## [1.0.4] - 2018-10-21 61 | 62 | ### Changed 63 | 64 | - Build with Xcode 10 and macOS Mojave 65 | 66 | - Migrate to Swift 4.2 67 | 68 | ## [1.0.3] - 2018-03-27 69 | 70 | ### Added 71 | 72 | - Add social sharing 73 | 74 | ### Changed 75 | 76 | - Code refactor 77 | 78 | - Build with new Xcode's build system 79 | 80 | ## [1.0.2] - 2017-09-24 81 | 82 | ### Changed 83 | 84 | - Update to Swift 4 85 | 86 | - Compiled with Xcode 9 87 | 88 | ## [1.0.1] - 2017-07-14 89 | 90 | ### Fixed 91 | 92 | - Fix compatibility issues with 10.11, 10.12beta 93 | 94 | ## [1.0.0] - 2017-07-11 95 | 96 | - Initial release 97 | 98 | --- 99 | 100 | ## Authors 101 | 102 | Idea & design: [Yuriy Oparenko](http://oparenko.com/) 103 | 104 | Development: [Sasha Prokhorenko](https://twitter.com/minikin) 105 | 106 | --- 107 | 108 | ## Tips 109 | 110 | - Use this app wisely. 111 | 112 | - Reboot your Mac after app use. 113 | 114 | --- 115 | 116 | ## License 117 | 118 | Sketch Cache Cleaner is distributed under the [MIT license](https://github.com/yo-op/sketchcachecleaner/blob/master/LICENSE.md). 119 | -------------------------------------------------------------------------------- /assets/SketchCacheCleaner.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/assets/SketchCacheCleaner.sketch -------------------------------------------------------------------------------- /assets/Sketch_Cache_Cleaner_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/assets/Sketch_Cache_Cleaner_Logo.png -------------------------------------------------------------------------------- /assets/catalina/catalina_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/assets/catalina/catalina_1.png -------------------------------------------------------------------------------- /assets/catalina/catalina_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/assets/catalina/catalina_2.png -------------------------------------------------------------------------------- /assets/catalina/catalina_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/assets/catalina/catalina_3.png -------------------------------------------------------------------------------- /assets/catalina/catalina_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/assets/catalina/catalina_4.png -------------------------------------------------------------------------------- /assets/catalina/catalina_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yo-op/sketchcachecleaner/94f1580fe4c16db2addf827facd2cbf65431cffb/assets/catalina/catalina_5.png --------------------------------------------------------------------------------