From fd652e4c647d7bf31c0dad4651330f3e8f892c28 Mon Sep 17 00:00:00 2001 From: Alin Date: Sun, 12 Nov 2023 20:59:30 -0700 Subject: [PATCH] initial --- .github/ISSUE_TEMPLATE/bug_report.md | 38 ++ .github/ISSUE_TEMPLATE/feature_request.md | 20 + .gitignore | 91 +++ Builds/ExportOptions.plist | 10 + Builds/changes.md | 11 + Pearcleaner.xcodeproj/project.pbxproj | 631 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/swiftpm/Package.resolved | 14 + .../xcschemes/Pearcleaner Debug.xcscheme | 77 +++ .../xcschemes/Pearcleaner Release.xcscheme | 103 +++ .../xcschemes/PearcleanerSentinel.xcscheme | 78 +++ Pearcleaner/Logic/AppCommands.swift | 106 +++ Pearcleaner/Logic/AppState.swift | 169 +++++ Pearcleaner/Logic/DeepLink.swift | 41 ++ Pearcleaner/Logic/Locations.swift | 105 +++ Pearcleaner/Logic/Logic.swift | 362 ++++++++++ Pearcleaner/Logic/Shapes.swift | 599 +++++++++++++++++ Pearcleaner/Logic/Styles.swift | 418 ++++++++++++ Pearcleaner/Logic/Utilities.swift | 509 ++++++++++++++ Pearcleaner/PearcleanerApp.swift | 92 +++ .../AccentColor.colorset/Contents.json | 38 ++ .../AppIcon.appiconset/Contents.json | 68 ++ .../AppIcon.appiconset/icon_128x128.png | Bin 0 -> 7360 bytes .../AppIcon.appiconset/icon_128x128@2x.png | Bin 0 -> 16749 bytes .../AppIcon.appiconset/icon_16x16.png | Bin 0 -> 662 bytes .../AppIcon.appiconset/icon_16x16@2x.png | Bin 0 -> 1437 bytes .../AppIcon.appiconset/icon_256x256.png | Bin 0 -> 16749 bytes .../AppIcon.appiconset/icon_256x256@2x.png | Bin 0 -> 39998 bytes .../AppIcon.appiconset/icon_32x32.png | Bin 0 -> 1437 bytes .../AppIcon.appiconset/icon_32x32@2x.png | Bin 0 -> 3222 bytes .../AppIcon.appiconset/icon_512x512.png | Bin 0 -> 39998 bytes .../AppIcon.appiconset/icon_512x512@2x.png | Bin 0 -> 96757 bytes .../Resources/Assets.xcassets/Contents.json | 6 + .../logo.imageset/Contents.json | 21 + .../logo.imageset/logo_combo.png | Bin 0 -> 20291 bytes .../mode.colorset/Contents.json | 38 ++ Pearcleaner/Resources/Info.plist | 19 + .../Resources/Pearcleaner.entitlements | 10 + .../com.alienator88.PearcleanerSentinel.plist | 16 + Pearcleaner/Settings/About.swift | 172 +++++ Pearcleaner/Settings/General.swift | 64 ++ Pearcleaner/Settings/Permissions.swift | 104 +++ Pearcleaner/Settings/Sentinel.swift | 52 ++ Pearcleaner/Settings/SettingsWindow.swift | 57 ++ Pearcleaner/Settings/Update.swift | 186 ++++++ Pearcleaner/Views/AppListItems.swift | 90 +++ Pearcleaner/Views/AppListView.swift | 213 ++++++ Pearcleaner/Views/ContentView.swift | 42 ++ Pearcleaner/Views/DropTarget.swift | 168 +++++ Pearcleaner/Views/FilesView.swift | 443 ++++++++++++ Pearcleaner/Views/TopBar.swift | 104 +++ Pearcleaner/Views/TrashView.swift | 19 + .../PearcleanerSentinel.entitlements | 5 + PearcleanerSentinel/main.swift | 285 ++++++++ README.md | 2 + 56 files changed, 5711 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .gitignore create mode 100644 Builds/ExportOptions.plist create mode 100644 Builds/changes.md create mode 100644 Pearcleaner.xcodeproj/project.pbxproj create mode 100644 Pearcleaner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Pearcleaner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Pearcleaner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 Pearcleaner.xcodeproj/xcshareddata/xcschemes/Pearcleaner Debug.xcscheme create mode 100644 Pearcleaner.xcodeproj/xcshareddata/xcschemes/Pearcleaner Release.xcscheme create mode 100644 Pearcleaner.xcodeproj/xcshareddata/xcschemes/PearcleanerSentinel.xcscheme create mode 100644 Pearcleaner/Logic/AppCommands.swift create mode 100644 Pearcleaner/Logic/AppState.swift create mode 100644 Pearcleaner/Logic/DeepLink.swift create mode 100644 Pearcleaner/Logic/Locations.swift create mode 100644 Pearcleaner/Logic/Logic.swift create mode 100644 Pearcleaner/Logic/Shapes.swift create mode 100644 Pearcleaner/Logic/Styles.swift create mode 100644 Pearcleaner/Logic/Utilities.swift create mode 100644 Pearcleaner/PearcleanerApp.swift create mode 100644 Pearcleaner/Resources/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_128x128.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_16x16.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_256x256.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_32x32.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_512x512.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/Contents.json create mode 100644 Pearcleaner/Resources/Assets.xcassets/logo.imageset/Contents.json create mode 100644 Pearcleaner/Resources/Assets.xcassets/logo.imageset/logo_combo.png create mode 100644 Pearcleaner/Resources/Assets.xcassets/mode.colorset/Contents.json create mode 100644 Pearcleaner/Resources/Info.plist create mode 100644 Pearcleaner/Resources/Pearcleaner.entitlements create mode 100644 Pearcleaner/Resources/com.alienator88.PearcleanerSentinel.plist create mode 100644 Pearcleaner/Settings/About.swift create mode 100644 Pearcleaner/Settings/General.swift create mode 100644 Pearcleaner/Settings/Permissions.swift create mode 100644 Pearcleaner/Settings/Sentinel.swift create mode 100644 Pearcleaner/Settings/SettingsWindow.swift create mode 100644 Pearcleaner/Settings/Update.swift create mode 100644 Pearcleaner/Views/AppListItems.swift create mode 100644 Pearcleaner/Views/AppListView.swift create mode 100644 Pearcleaner/Views/ContentView.swift create mode 100644 Pearcleaner/Views/DropTarget.swift create mode 100644 Pearcleaner/Views/FilesView.swift create mode 100644 Pearcleaner/Views/TopBar.swift create mode 100644 Pearcleaner/Views/TrashView.swift create mode 100644 PearcleanerSentinel/PearcleanerSentinel.entitlements create mode 100644 PearcleanerSentinel/main.swift create mode 100644 README.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f20167 --- /dev/null +++ b/.gitignore @@ -0,0 +1,91 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ +.DS_Store diff --git a/Builds/ExportOptions.plist b/Builds/ExportOptions.plist new file mode 100644 index 0000000..ae1ab83 --- /dev/null +++ b/Builds/ExportOptions.plist @@ -0,0 +1,10 @@ + + + + + method + mac-application + teamID + lupascu.marius@gmail.com + + diff --git a/Builds/changes.md b/Builds/changes.md new file mode 100644 index 0000000..a44c846 --- /dev/null +++ b/Builds/changes.md @@ -0,0 +1,11 @@ +## New Features + +- N/A + +## Fixed Issues + +- N/A + +## Changes + +- N/A diff --git a/Pearcleaner.xcodeproj/project.pbxproj b/Pearcleaner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b62be2c --- /dev/null +++ b/Pearcleaner.xcodeproj/project.pbxproj @@ -0,0 +1,631 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + C72893052AFD42E600C8C1CD /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C72893042AFD42E600C8C1CD /* DeepLink.swift */; }; + C72893122AFD51EA00C8C1CD /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C72893112AFD51EA00C8C1CD /* main.swift */; }; + C7575D382B0181FC006A600A /* FileWatcher in Frameworks */ = {isa = PBXBuildFile; productRef = C7575D372B0181FC006A600A /* FileWatcher */; }; + C7575D392B0182DE006A600A /* PearcleanerSentinel in CopyFiles */ = {isa = PBXBuildFile; fileRef = C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + C76D08482AF83C3F00D07867 /* Update.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D08472AF83C3F00D07867 /* Update.swift */; }; + C76D084A2AF83C6E00D07867 /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D08492AF83C6E00D07867 /* General.swift */; }; + C76D084C2AF83C9D00D07867 /* Permissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D084B2AF83C9D00D07867 /* Permissions.swift */; }; + C76D08512AF850F300D07867 /* About.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D08502AF850F300D07867 /* About.swift */; }; + C76D08552AF89CDE00D07867 /* AppListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D08542AF89CDE00D07867 /* AppListView.swift */; }; + C77B90042AF18E2E009CC655 /* PearcleanerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90032AF18E2E009CC655 /* PearcleanerApp.swift */; }; + C77B90062AF18E2E009CC655 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90052AF18E2E009CC655 /* ContentView.swift */; }; + C77B90082AF18E2F009CC655 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C77B90072AF18E2F009CC655 /* Assets.xcassets */; }; + C77B90162AF19377009CC655 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90152AF19377009CC655 /* AppState.swift */; }; + C77B90182AF19382009CC655 /* AppCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90172AF19382009CC655 /* AppCommands.swift */; }; + C77B901A2AF1938F009CC655 /* Logic.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90192AF1938F009CC655 /* Logic.swift */; }; + C77B901C2AF193A3009CC655 /* Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B901B2AF193A3009CC655 /* Styles.swift */; }; + C77B901E2AF1A9DB009CC655 /* SettingsWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B901D2AF1A9DB009CC655 /* SettingsWindow.swift */; }; + C77B90232AF2D616009CC655 /* FilesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90222AF2D616009CC655 /* FilesView.swift */; }; + C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */ = {isa = PBXBuildFile; fileRef = C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */; }; + C7D31D462AFDA90C00C7ED9E /* Sentinel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D452AFDA90C00C7ED9E /* Sentinel.swift */; }; + C7D31D482AFEB23700C7ED9E /* TopBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D472AFEB23700C7ED9E /* TopBar.swift */; }; + C7D31D4A2AFEB26700C7ED9E /* AppListItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D492AFEB26700C7ED9E /* AppListItems.swift */; }; + C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D502AFF00F300C7ED9E /* Locations.swift */; }; + C7D31D532B0048BE00C7ED9E /* TrashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D522B0048BE00C7ED9E /* TrashView.swift */; }; + C7D31D552B008CB900C7ED9E /* Shapes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D542B008CB900C7ED9E /* Shapes.swift */; }; + C7D31D592B00A49300C7ED9E /* DropTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D582B00A49300C7ED9E /* DropTarget.swift */; }; + C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F539372AF60865007DF1B2 /* Utilities.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + C728930D2AFD51EA00C8C1CD /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + C7A27E7D2AFD65C400166168 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 6; + files = ( + C7575D392B0182DE006A600A /* PearcleanerSentinel in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + C72893042AFD42E600C8C1CD /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = ""; }; + C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = PearcleanerSentinel; sourceTree = BUILT_PRODUCTS_DIR; }; + C72893112AFD51EA00C8C1CD /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + C76D08472AF83C3F00D07867 /* Update.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Update.swift; sourceTree = ""; }; + C76D08492AF83C6E00D07867 /* General.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = General.swift; sourceTree = ""; }; + C76D084B2AF83C9D00D07867 /* Permissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Permissions.swift; sourceTree = ""; }; + C76D084D2AF84D8C00D07867 /* Builds */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Builds; sourceTree = ""; }; + C76D08502AF850F300D07867 /* About.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = About.swift; sourceTree = ""; }; + C76D08542AF89CDE00D07867 /* AppListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppListView.swift; sourceTree = ""; }; + C77B90002AF18E2E009CC655 /* Pearcleaner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Pearcleaner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C77B90032AF18E2E009CC655 /* PearcleanerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PearcleanerApp.swift; sourceTree = ""; }; + C77B90052AF18E2E009CC655 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + C77B90072AF18E2F009CC655 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C77B90142AF18E7C009CC655 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C77B90152AF19377009CC655 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; + C77B90172AF19382009CC655 /* AppCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCommands.swift; sourceTree = ""; }; + C77B90192AF1938F009CC655 /* Logic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logic.swift; sourceTree = ""; }; + C77B901B2AF193A3009CC655 /* Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styles.swift; sourceTree = ""; }; + C77B901D2AF1A9DB009CC655 /* SettingsWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsWindow.swift; sourceTree = ""; }; + C77B90222AF2D616009CC655 /* FilesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesView.swift; sourceTree = ""; }; + C77B90242AF2D796009CC655 /* Pearcleaner.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Pearcleaner.entitlements; sourceTree = ""; }; + C7A27E7F2AFD70DD00166168 /* PearcleanerSentinel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PearcleanerSentinel.entitlements; sourceTree = ""; }; + C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.alienator88.PearcleanerSentinel.plist; sourceTree = ""; }; + C7D31D452AFDA90C00C7ED9E /* Sentinel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sentinel.swift; sourceTree = ""; }; + C7D31D472AFEB23700C7ED9E /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.swift; sourceTree = ""; }; + C7D31D492AFEB26700C7ED9E /* AppListItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppListItems.swift; sourceTree = ""; }; + C7D31D502AFF00F300C7ED9E /* Locations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locations.swift; sourceTree = ""; }; + C7D31D522B0048BE00C7ED9E /* TrashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrashView.swift; sourceTree = ""; }; + C7D31D542B008CB900C7ED9E /* Shapes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shapes.swift; sourceTree = ""; }; + C7D31D582B00A49300C7ED9E /* DropTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropTarget.swift; sourceTree = ""; }; + C7F539372AF60865007DF1B2 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C728930C2AFD51EA00C8C1CD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C7575D382B0181FC006A600A /* FileWatcher in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C77B8FFD2AF18E2E009CC655 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C72893072AFD442600C8C1CD /* Logic */ = { + isa = PBXGroup; + children = ( + C77B90192AF1938F009CC655 /* Logic.swift */, + C77B90172AF19382009CC655 /* AppCommands.swift */, + C77B90152AF19377009CC655 /* AppState.swift */, + C7F539372AF60865007DF1B2 /* Utilities.swift */, + C72893042AFD42E600C8C1CD /* DeepLink.swift */, + C77B901B2AF193A3009CC655 /* Styles.swift */, + C7D31D502AFF00F300C7ED9E /* Locations.swift */, + C7D31D542B008CB900C7ED9E /* Shapes.swift */, + ); + path = Logic; + sourceTree = ""; + }; + C72893102AFD51EA00C8C1CD /* PearcleanerSentinel */ = { + isa = PBXGroup; + children = ( + C7A27E822AFD996100166168 /* Resources */, + C7A27E7F2AFD70DD00166168 /* PearcleanerSentinel.entitlements */, + C72893112AFD51EA00C8C1CD /* main.swift */, + ); + path = PearcleanerSentinel; + sourceTree = ""; + }; + C72893162AFD531500C8C1CD /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + C76D08462AF83C2F00D07867 /* Settings */ = { + isa = PBXGroup; + children = ( + C77B901D2AF1A9DB009CC655 /* SettingsWindow.swift */, + C76D08492AF83C6E00D07867 /* General.swift */, + C76D084B2AF83C9D00D07867 /* Permissions.swift */, + C7D31D452AFDA90C00C7ED9E /* Sentinel.swift */, + C76D08472AF83C3F00D07867 /* Update.swift */, + C76D08502AF850F300D07867 /* About.swift */, + ); + path = Settings; + sourceTree = ""; + }; + C76D084F2AF84E0100D07867 /* Resources */ = { + isa = PBXGroup; + children = ( + C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */, + C77B90142AF18E7C009CC655 /* Info.plist */, + C77B90072AF18E2F009CC655 /* Assets.xcassets */, + C77B90242AF2D796009CC655 /* Pearcleaner.entitlements */, + ); + path = Resources; + sourceTree = ""; + }; + C77B8FF72AF18E2E009CC655 = { + isa = PBXGroup; + children = ( + C76D084D2AF84D8C00D07867 /* Builds */, + C77B90022AF18E2E009CC655 /* Pearcleaner */, + C72893102AFD51EA00C8C1CD /* PearcleanerSentinel */, + C77B90012AF18E2E009CC655 /* Products */, + C72893162AFD531500C8C1CD /* Frameworks */, + ); + sourceTree = ""; + }; + C77B90012AF18E2E009CC655 /* Products */ = { + isa = PBXGroup; + children = ( + C77B90002AF18E2E009CC655 /* Pearcleaner.app */, + C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */, + ); + name = Products; + sourceTree = ""; + }; + C77B90022AF18E2E009CC655 /* Pearcleaner */ = { + isa = PBXGroup; + children = ( + C77B90032AF18E2E009CC655 /* PearcleanerApp.swift */, + C76D084F2AF84E0100D07867 /* Resources */, + C76D08462AF83C2F00D07867 /* Settings */, + C77B901F2AF1B390009CC655 /* Views */, + C72893072AFD442600C8C1CD /* Logic */, + ); + path = Pearcleaner; + sourceTree = ""; + }; + C77B901F2AF1B390009CC655 /* Views */ = { + isa = PBXGroup; + children = ( + C77B90052AF18E2E009CC655 /* ContentView.swift */, + C77B90222AF2D616009CC655 /* FilesView.swift */, + C76D08542AF89CDE00D07867 /* AppListView.swift */, + C7D31D472AFEB23700C7ED9E /* TopBar.swift */, + C7D31D492AFEB26700C7ED9E /* AppListItems.swift */, + C7D31D522B0048BE00C7ED9E /* TrashView.swift */, + C7D31D582B00A49300C7ED9E /* DropTarget.swift */, + ); + path = Views; + sourceTree = ""; + }; + C7A27E822AFD996100166168 /* Resources */ = { + isa = PBXGroup; + children = ( + ); + path = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C728930E2AFD51EA00C8C1CD /* PearcleanerSentinel */ = { + isa = PBXNativeTarget; + buildConfigurationList = C72893132AFD51EA00C8C1CD /* Build configuration list for PBXNativeTarget "PearcleanerSentinel" */; + buildPhases = ( + C728930B2AFD51EA00C8C1CD /* Sources */, + C728930C2AFD51EA00C8C1CD /* Frameworks */, + C728930D2AFD51EA00C8C1CD /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PearcleanerSentinel; + packageProductDependencies = ( + C7575D372B0181FC006A600A /* FileWatcher */, + ); + productName = PeakPurgeMonitor; + productReference = C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */; + productType = "com.apple.product-type.tool"; + }; + C77B8FFF2AF18E2E009CC655 /* Pearcleaner */ = { + isa = PBXNativeTarget; + buildConfigurationList = C77B900F2AF18E2F009CC655 /* Build configuration list for PBXNativeTarget "Pearcleaner" */; + buildPhases = ( + C77B8FFC2AF18E2E009CC655 /* Sources */, + C77B8FFD2AF18E2E009CC655 /* Frameworks */, + C77B8FFE2AF18E2E009CC655 /* Resources */, + C7A27E7D2AFD65C400166168 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Pearcleaner; + packageProductDependencies = ( + ); + productName = PeakPurge; + productReference = C77B90002AF18E2E009CC655 /* Pearcleaner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C77B8FF82AF18E2E009CC655 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1500; + TargetAttributes = { + C728930E2AFD51EA00C8C1CD = { + CreatedOnToolsVersion = 15.0.1; + }; + C77B8FFF2AF18E2E009CC655 = { + CreatedOnToolsVersion = 15.0.1; + }; + }; + }; + buildConfigurationList = C77B8FFB2AF18E2E009CC655 /* Build configuration list for PBXProject "Pearcleaner" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = C77B8FF72AF18E2E009CC655; + packageReferences = ( + C7575D362B0181F3006A600A /* XCRemoteSwiftPackageReference "FileWatcher" */, + ); + productRefGroup = C77B90012AF18E2E009CC655 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C77B8FFF2AF18E2E009CC655 /* Pearcleaner */, + C728930E2AFD51EA00C8C1CD /* PearcleanerSentinel */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C77B8FFE2AF18E2E009CC655 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C77B90082AF18E2F009CC655 /* Assets.xcassets in Resources */, + C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C728930B2AFD51EA00C8C1CD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C72893122AFD51EA00C8C1CD /* main.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C77B8FFC2AF18E2E009CC655 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C76D08482AF83C3F00D07867 /* Update.swift in Sources */, + C77B90162AF19377009CC655 /* AppState.swift in Sources */, + C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */, + C77B901A2AF1938F009CC655 /* Logic.swift in Sources */, + C7D31D532B0048BE00C7ED9E /* TrashView.swift in Sources */, + C7D31D462AFDA90C00C7ED9E /* Sentinel.swift in Sources */, + C7D31D592B00A49300C7ED9E /* DropTarget.swift in Sources */, + C77B90062AF18E2E009CC655 /* ContentView.swift in Sources */, + C77B901C2AF193A3009CC655 /* Styles.swift in Sources */, + C72893052AFD42E600C8C1CD /* DeepLink.swift in Sources */, + C76D084C2AF83C9D00D07867 /* Permissions.swift in Sources */, + C76D084A2AF83C6E00D07867 /* General.swift in Sources */, + C77B90042AF18E2E009CC655 /* PearcleanerApp.swift in Sources */, + C7D31D552B008CB900C7ED9E /* Shapes.swift in Sources */, + C76D08512AF850F300D07867 /* About.swift in Sources */, + C77B90182AF19382009CC655 /* AppCommands.swift in Sources */, + C7D31D4A2AFEB26700C7ED9E /* AppListItems.swift in Sources */, + C77B901E2AF1A9DB009CC655 /* SettingsWindow.swift in Sources */, + C7D31D482AFEB23700C7ED9E /* TopBar.swift in Sources */, + C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */, + C76D08552AF89CDE00D07867 /* AppListView.swift in Sources */, + C77B90232AF2D616009CC655 /* FilesView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C72893142AFD51EA00C8C1CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = PearcleanerSentinel/PearcleanerSentinel.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = BK8443AXLU; + ENABLE_HARDENED_RUNTIME = YES; + MACOSX_DEPLOYMENT_TARGET = 13.0; + PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.PearcleanerSentinel; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + C72893152AFD51EA00C8C1CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = PearcleanerSentinel/PearcleanerSentinel.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = BK8443AXLU; + ENABLE_HARDENED_RUNTIME = YES; + MACOSX_DEPLOYMENT_TARGET = 13.0; + PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.PearcleanerSentinel; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + C77B900D2AF18E2F009CC655 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = ""; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + C77B900E2AF18E2F009CC655 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = ""; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + C77B90102AF18E2F009CC655 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = Pearcleaner/Resources/Pearcleaner.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = BK8443AXLU; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = Pearcleaner/Resources/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Pearcleaner; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; + INFOPLIST_KEY_NSAppleEventsUsageDescription = "App needs to send apple events to FInder to delete files"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSSystemAdministrationUsageDescription = "Requires full disk access to be able to delete files in locations with no permission"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + C77B90112AF18E2F009CC655 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = Pearcleaner/Resources/Pearcleaner.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = BK8443AXLU; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = Pearcleaner/Resources/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Pearcleaner; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; + INFOPLIST_KEY_NSAppleEventsUsageDescription = "App needs to send apple events to FInder to delete files"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSSystemAdministrationUsageDescription = "Requires full disk access to be able to delete files in locations with no permission"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C72893132AFD51EA00C8C1CD /* Build configuration list for PBXNativeTarget "PearcleanerSentinel" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C72893142AFD51EA00C8C1CD /* Debug */, + C72893152AFD51EA00C8C1CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C77B8FFB2AF18E2E009CC655 /* Build configuration list for PBXProject "Pearcleaner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C77B900D2AF18E2F009CC655 /* Debug */, + C77B900E2AF18E2F009CC655 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C77B900F2AF18E2F009CC655 /* Build configuration list for PBXNativeTarget "Pearcleaner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C77B90102AF18E2F009CC655 /* Debug */, + C77B90112AF18E2F009CC655 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + C7575D362B0181F3006A600A /* XCRemoteSwiftPackageReference "FileWatcher" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/eonist/FileWatcher.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.2.3; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + C7575D372B0181FC006A600A /* FileWatcher */ = { + isa = XCSwiftPackageProductDependency; + package = C7575D362B0181F3006A600A /* XCRemoteSwiftPackageReference "FileWatcher" */; + productName = FileWatcher; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = C77B8FF82AF18E2E009CC655 /* Project object */; +} diff --git a/Pearcleaner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Pearcleaner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Pearcleaner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Pearcleaner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Pearcleaner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Pearcleaner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Pearcleaner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Pearcleaner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..89f2a9b --- /dev/null +++ b/Pearcleaner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "filewatcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/eonist/FileWatcher.git", + "state" : { + "revision" : "e67c2a99502eade343fecabeca8c57e749a55b59", + "version" : "0.2.3" + } + } + ], + "version" : 2 +} diff --git a/Pearcleaner.xcodeproj/xcshareddata/xcschemes/Pearcleaner Debug.xcscheme b/Pearcleaner.xcodeproj/xcshareddata/xcschemes/Pearcleaner Debug.xcscheme new file mode 100644 index 0000000..9aa3ff6 --- /dev/null +++ b/Pearcleaner.xcodeproj/xcshareddata/xcschemes/Pearcleaner Debug.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pearcleaner.xcodeproj/xcshareddata/xcschemes/Pearcleaner Release.xcscheme b/Pearcleaner.xcodeproj/xcshareddata/xcschemes/Pearcleaner Release.xcscheme new file mode 100644 index 0000000..0f406db --- /dev/null +++ b/Pearcleaner.xcodeproj/xcshareddata/xcschemes/Pearcleaner Release.xcscheme @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pearcleaner.xcodeproj/xcshareddata/xcschemes/PearcleanerSentinel.xcscheme b/Pearcleaner.xcodeproj/xcshareddata/xcschemes/PearcleanerSentinel.xcscheme new file mode 100644 index 0000000..0134fda --- /dev/null +++ b/Pearcleaner.xcodeproj/xcshareddata/xcschemes/PearcleanerSentinel.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pearcleaner/Logic/AppCommands.swift b/Pearcleaner/Logic/AppCommands.swift new file mode 100644 index 0000000..01c94ef --- /dev/null +++ b/Pearcleaner/Logic/AppCommands.swift @@ -0,0 +1,106 @@ +// +// AppCommands.swift +// Pearcleaner +// +// Created by Alin Lupascu on 10/31/23. +// + +import SwiftUI + +struct AppCommands: Commands { + + let appState: AppState + + init(appState: AppState) { + self.appState = appState + } + + var body: some Commands { + + // Pearcleaner Menu + CommandGroup(replacing: .appInfo) { + + Button { + loadGithubReleases(appState: appState, manual: true) + } label: { + Text("Updates") + } + .keyboardShortcut("u", modifiers: .command) + + Button { + withAnimation(.easeInOut(duration: 0.5)) { + // Refresh Apps list + let sortedApps = getSortedApps() + appState.sortedApps.userApps = sortedApps.userApps + appState.sortedApps.systemApps = sortedApps.systemApps + } + } label: { + Text("Refresh Apps") + } + .keyboardShortcut("r", modifiers: .command) + + } + + + + // Edit Menu + CommandGroup(replacing: .undoRedo) { + Button + { + undoTrash(appState: appState) { + let sortedApps = getSortedApps() + appState.sortedApps.userApps = [] + appState.sortedApps.systemApps = [] + appState.sortedApps.userApps = sortedApps.userApps + appState.sortedApps.systemApps = sortedApps.systemApps + } + } label: { + Label("Undo Removal", systemImage: "clear") + } + .keyboardShortcut("z", modifiers: .command) + } + + + + // GitHub Menu + CommandMenu(Text("GitHub", comment: "Github Repo")) { + Button + { + NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner")!) + } label: { + Label("View Repository", systemImage: "paperplane") + } + + + Button + { + NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner/releases")!) + } label: { + Label("View Releases", systemImage: "paperplane") + } + + + Button + { + NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner/issues")!) + } label: { + Label("View Issues", systemImage: "paperplane") + } + + + Divider() + + + Button + { + NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner/issues/new/choose")!) + } label: { + Label("Submit New Issue", systemImage: "paperplane") + } + } + + + + } +} + diff --git a/Pearcleaner/Logic/AppState.swift b/Pearcleaner/Logic/AppState.swift new file mode 100644 index 0000000..15c9348 --- /dev/null +++ b/Pearcleaner/Logic/AppState.swift @@ -0,0 +1,169 @@ +// +// AppState.swift +// Pearcleaner +// +// Created by Alin Lupascu on 10/31/23. +// + +import Foundation +import SwiftUI + +let home = FileManager.default.homeDirectoryForCurrentUser.path + +class AppState: ObservableObject +{ + @Published var showFiles: Bool = false + @Published var appInfo: AppInfo + @Published var paths: [URL] = [] + @Published var sortedApps: (userApps: [AppInfo], systemApps: [AppInfo]) = ([], []) + @Published var selectedItems = Set() + @Published var alertType = AlertType.off + @Published var currentView = CurrentDetailsView.empty + @Published var showAlert: Bool = false + @Published var sidebar: Bool = true + @Published var isReminderVisible: Bool = false + @Published var releases = [Release]() + + //Window +// @Published var winWidth: CGFloat = 1020 + + init() { + self.appInfo = AppInfo( + id: UUID(), + path: URL(fileURLWithPath: ""), + bundleIdentifier: "", + appName: "", + appVersion: "", + appIcon: nil + ) + } +} + +struct AppInfo: Identifiable, Hashable { + let id: UUID + let path: URL + let bundleIdentifier: String + let appName: String + let appVersion: String + let appIcon: NSImage? + + static let empty = AppInfo(id: UUID(), path: URL(fileURLWithPath: ""), bundleIdentifier: "", appName: "", appVersion: "", appIcon: nil) +} + + +enum CurrentTabView:Int +{ + case general + case permissions + case sentinel + case update + case about + + var title: String { + switch self { + case .general: return "General" + case .permissions: return "Permissions" + case .sentinel: return "Sentinel" + case .update: return "Update" + case .about: return "About" + } + } +} + +enum CurrentDetailsView:Int +{ + case empty + case files +} + +enum AlertType:Int +{ + case diskAccess + case update + case no_update + case restartApp + case off +} + + + +enum DisplayMode: Int, CaseIterable { + case system, dark, light + + var colorScheme: ColorScheme? { + get { + switch self { + case .system: return nil + case .dark: return ColorScheme.dark + case .light: return ColorScheme.light + } + } + set { + switch newValue { + case .none: + self = .system + case .dark?: + self = .dark + case .light?: + self = .light + default: + break + } + } + } + + var description: String { + switch self { + case .system: return "System" + case .dark: return "Dark" + case .light: return "Light" + } + } +} + + + +//let (cacheDir, tempDir) = darwinCT() +//let locations: [String] = [ +// "\(home)/Library", +// "\(home)/Library/Application Scripts", +// "\(home)/Library/Application Support", +// "\(home)/Library/Application Support/CrashReporter", +// "\(home)/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments", +// "\(home)/Library/Containers", +// "\(home)/Library/Group Containers", +// "\(home)/Library/Caches", +// "\(home)/Library/HTTPStorages", +// "\(home)/Library/Group Containers", +// "\(home)/Library/Internet Plug-Ins", +// "\(home)/Library/LaunchAgents", +// "\(home)/Library/Logs", +// "\(home)/Library/Preferences", +// "\(home)/Library/Preferences/ByHost", +// "\(home)/Library/Saved Application State", +// "\(home)/Library/WebKit", +// "/Users/Shared", +// "/Users/Library", +// "/Library", +// "/Library/Application Support", +// "/Library/Application Support/CrashReporter", +// "/Library/Caches", +// "/Library/Extensions", +// "/Library/Internet Plug-Ins", +// "/Library/LaunchAgents", +// "/Library/LaunchDaemons", +// "/Library/Logs", +// "/Library/Logs/DiagnosticReports", +// "/Library/Preferences", +// "/Library/PrivilegedHelperTools", +// "/private/var/db/receipts", +// "/private/tmp", +// "/usr/local/bin", +// "/usr/local/etc", +// "/usr/local/opt", +// "/usr/local/sbin", +// "/usr/local/share", +// "/usr/local/var", +// cacheDir, +// tempDir +//] diff --git a/Pearcleaner/Logic/DeepLink.swift b/Pearcleaner/Logic/DeepLink.swift new file mode 100644 index 0000000..0949af2 --- /dev/null +++ b/Pearcleaner/Logic/DeepLink.swift @@ -0,0 +1,41 @@ +// +// DeepLink.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/9/23. +// + +import Foundation +import SwiftUI + +class DeeplinkManager { + + class DeepLinkConstants { + static let scheme = "pear" + static let host = "com.alienator88.Pearcleaner" + static let query = "path" + } + + func manage(url: URL, appState: AppState) { + guard url.scheme == DeepLinkConstants.scheme, + url.host == DeepLinkConstants.host, + let components = URLComponents(url: url, resolvingAgainstBaseURL: true), + let queryItems = components.queryItems + else { + print("URL does not match the expected scheme and host") + return + } + + if let path = queryItems.first(where: { $0.name == DeepLinkConstants.query })?.value { + let pathURL = URL(fileURLWithPath: path) + let appInfo = getAppInfo(atPath: pathURL) + updateOnMain { + appState.appInfo = appInfo! + findPathsForApp(appState: appState, appInfo: appState.appInfo) + appState.currentView = .files + } + } else { + print("No path query parameter found in the URL") + } + } +} diff --git a/Pearcleaner/Logic/Locations.swift b/Pearcleaner/Logic/Locations.swift new file mode 100644 index 0000000..6dbb0a8 --- /dev/null +++ b/Pearcleaner/Logic/Locations.swift @@ -0,0 +1,105 @@ +// +// Locations.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/10/23. +// + +import Foundation + + +struct Locations { + struct Category { + let name: String + var paths: [String] + } + + let home: String + let cacheDir: String + let tempDir: String + + var apps: Category + var widgets: Category + var plugins: Category + + init() { + self.home = FileManager.default.homeDirectoryForCurrentUser.path + let (cacheDir, tempDir) = darwinCT() + self.cacheDir = cacheDir + self.tempDir = tempDir + + self.apps = Category(name: "Apps", paths: [ + "\(home)/Library", + "\(home)/Library/Application Scripts", + "\(home)/Library/Application Support", + "\(home)/Library/Application Support/CrashReporter", + "\(home)/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments", + "\(home)/Library/Containers", + "\(home)/Library/Group Containers", + "\(home)/Library/Caches", + "\(home)/Library/HTTPStorages", + "\(home)/Library/Group Containers", + "\(home)/Library/Internet Plug-Ins", + "\(home)/Library/LaunchAgents", + "\(home)/Library/Logs", + "\(home)/Library/Preferences", + "\(home)/Library/Preferences/ByHost", + "\(home)/Library/Saved Application State", + "\(home)/Library/WebKit", + "/Users/Shared", + "/Users/Library", + "/Library", + "/Library/Application Support", + "/Library/Application Support/CrashReporter", + "/Library/Caches", + "/Library/Extensions", + "/Library/Internet Plug-Ins", + "/Library/LaunchAgents", + "/Library/LaunchDaemons", + "/Library/Logs", + "/Library/Logs/DiagnosticReports", + "/Library/Preferences", + "/Library/PrivilegedHelperTools", + "/private/var/db/receipts", + "/private/tmp", + "/usr/local/bin", + "/usr/local/etc", + "/usr/local/opt", + "/usr/local/sbin", + "/usr/local/share", + "/usr/local/var", + cacheDir, + tempDir + ]) + + self.widgets = Category(name: "Widgets", paths: [ + // User + "~/Library/Widgets", + // System + "/Library/Widgets" + ]) + + self.plugins = Category(name: "Plugins", paths: [ + // User + "~/Library/Contextual Menu Items", + "~/Library/InputManagers", + "~/Library/Internet Plug-Ins", + "~/Library/Mail/Bundles", + "~/Library/PreferencePanes", + "~/Library/QuickLook", + "~/Library/QuickTime", + "~/Library/Screen Savers", + "~/Library/Spotlight", + // System + "/Library/Contextual Menu Items", + "/Library/InputManagers", + "/Library/Internet Plug-Ins", + "/Library/Mail/Bundles", + "/Library/PreferencePanes", + "/Library/QuickLook", + "/Library/QuickTime", + "/Library/Screen Savers", + "/Library/Spotlight", + ]) + } +} diff --git a/Pearcleaner/Logic/Logic.swift b/Pearcleaner/Logic/Logic.swift new file mode 100644 index 0000000..3e89a4a --- /dev/null +++ b/Pearcleaner/Logic/Logic.swift @@ -0,0 +1,362 @@ +// +// Logic.swift +// Pearcleaner +// +// Created by Alin Lupascu on 10/31/23. +// + +import Foundation +import SwiftUI + + +// Get list of apps and sort it +func getSortedApps() -> (systemApps: [AppInfo], userApps: [AppInfo]) { + let apps = getApplications() + let sortedSystemApps = apps.systemApps + .compactMap { getAppInfo(atPath: $0) } + .sorted { $0.appName.replacingOccurrences(of: ".", with: "").lowercased() < $1.appName.replacingOccurrences(of: ".", with: "").lowercased() } + let sortedUserApps = apps.userApps + .compactMap { getAppInfo(atPath: $0) } + .sorted { $0.appName.replacingOccurrences(of: ".", with: "").lowercased() < $1.appName.replacingOccurrences(of: ".", with: "").lowercased() } + + return (systemApps: sortedSystemApps, userApps: sortedUserApps) +} + + +// Get all applications from /Applications and ~/Applications +func getApplications() -> (systemApps: [URL], userApps: [URL]) { + let fileManager = FileManager.default + + // Define the paths for system and user applications + let systemAppsPath = "/Applications" + let userAppsPath = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Applications").path + + var systemApps: [URL] = [] + var userApps: [URL] = [] + + func collectAppPaths(at directoryPath: String, isSystem: Bool) { + do { + let appURLs = try fileManager.contentsOfDirectory(at: URL(fileURLWithPath: directoryPath), includingPropertiesForKeys: nil, options: []) + + for appURL in appURLs { + if appURL.pathExtension == "app" { + // Add the path to the appropriate list + if isSystem && !isRestricted(atPath: appURL) { + systemApps.append(appURL) + } else if !isSystem && !isRestricted(atPath: appURL) { + userApps.append(appURL) + } + } else if appURL.hasDirectoryPath { + // If it's a directory, recursively explore it + collectAppPaths(at: appURL.path, isSystem: isSystem) + } + } + } catch { + // Handle any potential errors here + print("Error: \(error)") + } + } + + // Collect system applications + collectAppPaths(at: systemAppsPath, isSystem: true) + + // Collect user applications + collectAppPaths(at: userAppsPath, isSystem: false) + + // Filter out unwanted system folders like /Applications/Utilities + systemApps = systemApps.filter { !$0.absoluteString.contains("/Applications/Utilities/") } + return (systemApps, userApps) +} + + +// Get app bundle information from provided path +func getAppInfo(atPath path: URL) -> AppInfo? { + if let bundle = Bundle(url: path) { + if let bundleIdentifier = bundle.bundleIdentifier, + let appVersion = bundle.infoDictionary?["CFBundleShortVersionString"] as? String, + var appIconFileName = bundle.infoDictionary?["CFBundleIconFile"] as? String { + var appIcon: NSImage? + var appName: String? + if let localizedName = bundle.localizedInfoDictionary?[kCFBundleNameKey as String] as? String { + appName = localizedName + } else if let bundleName = bundle.infoDictionary?["CFBundleName"] as? String { + appName = bundleName + } + // Check if the icon file name has an .icns extension, if not, add it + if !appIconFileName.hasSuffix(".icns") { + appIconFileName += ".icns" + } + + // Try to find the icon in the main bundle + if let iconPath = bundle.path(forResource: appIconFileName, ofType: nil), + let icon = NSImage(contentsOfFile: iconPath) { + appIcon = icon + } + + // If not found, try to find it in the resources directory + if appIcon == nil, + let resourcesPath = bundle.resourcePath { + let iconURL = URL(fileURLWithPath: resourcesPath).appendingPathComponent(appIconFileName) + if let icon = NSImage(contentsOfFile: iconURL.path) { + appIcon = icon + } + } + + // Convert the icon to a 100x100 PNG image + if let pngIcon = appIcon.flatMap({ convertICNSToPNG(icon: $0, size: NSSize(width: 100, height: 100)) }) { + appIcon = pngIcon + } + + if appIcon == nil { + print("App Icon not found for app at path: \(path)") + } + + return AppInfo(id: UUID(), path: path, bundleIdentifier: bundleIdentifier, appName: appName ?? "", appVersion: appVersion, appIcon: appIcon) + + } else { + print("One or more variables missing for app at path: \(path)") + } + } else { + print("Bundle not found at path: \(path)") + } + return nil +} + + + +// Get directory path for darwin cache and temp directories +func darwinCT() -> (String, String) { + let task = Process() + task.launchPath = "/bin/bash" + task.arguments = ["-c", "getconf DARWIN_USER_CACHE_DIR; getconf DARWIN_USER_TEMP_DIR"] + let pipe = Pipe() + task.standardOutput = pipe + task.launch() + let data = pipe.fileHandleForReading.readDataToEndOfFile() + if let output = String(data: data, encoding: .utf8) { + let components = output.components(separatedBy: "\n") + if components.count >= 2 { + var cacheDir = components[0].trimmingCharacters(in: .whitespacesAndNewlines) + var tempDir = components[1].trimmingCharacters(in: .whitespacesAndNewlines) + if cacheDir.hasSuffix("/") { + cacheDir.removeLast() + } + if tempDir.hasSuffix("/") { + tempDir.removeLast() + } + return (cacheDir, tempDir) + } + } + print("Could not get DARWIN_USER_CACHE_DIR or DARWIN_USER_TEMP_DIR") + return ("", "") +} + + + +// Check if app is running before deleting app files +func killApp(appId: String, completion: @escaping () -> Void = {}) { + let runningApps = NSWorkspace.shared.runningApplications + for app in runningApps { + if app.bundleIdentifier == appId { + app.terminate() + } + } + completion() +} + + + + +// Find all possible paths for an app based on name/bundle id +func findPathsForApp(appState: AppState, appInfo: AppInfo) { + Task(priority: .high) { + updateOnMain { + appState.paths = [] + } + var collection: [URL] = [] + if let url = URL(string: appInfo.path.absoluteString) { + // appState.paths.insert(url, at: 0) + collection.insert(url, at: 0) + } + let fileManager = FileManager.default + let dispatchGroup = DispatchGroup() + let bundleComponents = appInfo.bundleIdentifier.components(separatedBy: ".") + var bundle: String = "" + if bundleComponents.count >= 3 { // get last 2 or middle 2 components + bundle = bundleComponents[1...2].joined(separator: "").lowercased() + } + let nameL = appInfo.appName.pearFormat() + let bundleIdentifierL = appInfo.bundleIdentifier.pearFormat() + let locations = Locations() + + for location in locations.apps.paths { + dispatchGroup.enter() // Enter the dispatch group + + do { + let contents = try fileManager.contentsOfDirectory(atPath: location) + + for item in contents { + + let itemURL = URL(fileURLWithPath: location).appendingPathComponent(item) + let itemL = ("\(item)").replacingOccurrences(of: ".", with: "").replacingOccurrences(of: " ", with: "").lowercased() + + if collection.contains(itemURL) { + return + } + + if itemL.contains("comapple") { + if itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count > 4 && itemL.contains(nameL)) { + collection.append(itemURL) + } + } + else if itemL.contains("xcode") { + if itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count > 4 && itemL.contains(nameL)) { + collection.append(itemURL) + } + } else if itemL.contains("logi") && !itemL.contains("login") { + if itemL.contains(bundleComponents[1]) || itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count > 3 && itemL.contains(nameL)) { + collection.append(itemURL) + } + } else if itemL.contains("office") || itemL.contains("oneauth") || itemL.suffix(2).contains("ms") || itemL.contains("onenote") { + if itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count > 4 && itemL.contains(nameL)) { + collection.append(itemURL) + } + } else { + if itemL.contains(bundleIdentifierL) || itemL.contains(bundle) || (nameL.count > 3 && itemL.contains(nameL)) { + collection.append(itemURL) + } + } + } + } catch { + continue + } + + dispatchGroup.leave() // Leave the dispatch group + + dispatchGroup.notify(queue: .main) { + updateOnMain { + appState.paths = collection + appState.selectedItems = Set(collection) + } + } + + } + } +} + + + + +// Move files to trash using applescript/Finder so it asks for user password if needed +func moveFilesToTrash(at fileURLs: [URL], completion: @escaping () -> Void = {}) { + updateOnBackground { + let posixFiles = fileURLs.map { "POSIX file \"\($0.path)\", " }.joined().dropLast(3) + let scriptSource = """ + tell application \"Finder\" to delete { \(posixFiles)" } + """ + var error: NSDictionary? + if let scriptObject = NSAppleScript(source: scriptSource) { + let output: NSAppleEventDescriptor = scriptObject.executeAndReturnError(&error) + if let error = error { + print("Error: \(error)") + } else if let outputString = output.stringValue { + print(outputString) + } + } + DispatchQueue.main.async { + completion() + } + } +} + + +// Undo trash action +func undoTrash(appState: AppState, completion: @escaping () -> Void = {}) { + let scriptSource = """ + tell application "Finder" + activate + end tell + + tell application "System Events" + keystroke "z" using command down + end tell + + tell application "Pearcleaner" + activate + end tell + """ + var error: NSDictionary? + + updateOnBackground { + if let scriptObject = NSAppleScript(source: scriptSource) { + let output: NSAppleEventDescriptor = scriptObject.executeAndReturnError(&error) + if let error = error { + if let value = error["NSAppleScriptErrorNumber"] { + if value as! Int == 1002 { + _ = checkAndRequestAccessibilityAccess(appState: appState) + } + } + print("Error: \(error)") + } else if let outputString = output.stringValue { + print(outputString) + } + } + DispatchQueue.main.async { + completion() + } + } +} + + + + + + + + + + + + +//func isAppRunning(appName: String) -> Bool { +// let task = Process() +// task.executableURL = URL(fileURLWithPath: "/usr/bin/pgrep") +// task.arguments = ["-af", appName] +// +// let outputPipe = Pipe() +// task.standardOutput = outputPipe +// +// do { +// try task.run() +// } catch { +// print("Failed to run task: \(error)") +// return false +// } +// +// let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile() +// let output = String(decoding: outputData, as: UTF8.self) +// +// if output.isEmpty { +// return false +// } else { +// return true +// } +//} +// +//// Kill app if running +//func killApp2(appName: String, completion: @escaping () -> Void = {}) { +// if isAppRunning(appName: appName) { +// let task = Process() +// task.executableURL = URL(fileURLWithPath: "/usr/bin/pkill") +// task.arguments = ["-af", appName] +// +// do { +// try task.run() +// } catch { +// print("Failed to run task: \(error)") +// return +// } +// +// } +// completion() +//} diff --git a/Pearcleaner/Logic/Shapes.swift b/Pearcleaner/Logic/Shapes.swift new file mode 100644 index 0000000..86ef766 --- /dev/null +++ b/Pearcleaner/Logic/Shapes.swift @@ -0,0 +1,599 @@ +// +// Shapes.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/11/23. +// + +import Foundation +import SwiftUI + +// Pear Logo +struct Pear: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + let width = rect.size.width + let height = rect.size.height + path.move(to: CGPoint(x: 0.5985*width, y: 0.045*height)) + path.addCurve(to: CGPoint(x: 0.508*width, y: 0.141*height), control1: CGPoint(x: 0.571*width, y: 0.0635*height), control2: CGPoint(x: 0.521*width, y: 0.116*height)) + path.addLine(to: CGPoint(x: 0.4985*width, y: 0.159*height)) + path.addLine(to: CGPoint(x: 0.4725*width, y: 0.1325*height)) + path.addCurve(to: CGPoint(x: 0.318*width, y: 0.0975*height), control1: CGPoint(x: 0.433*width, y: 0.092*height), control2: CGPoint(x: 0.383*width, y: 0.0805*height)) + path.addCurve(to: CGPoint(x: 0.2105*width, y: 0.15*height), control1: CGPoint(x: 0.2875*width, y: 0.1055*height), control2: CGPoint(x: 0.231*width, y: 0.133*height)) + path.addLine(to: CGPoint(x: 0.1985*width, y: 0.16*height)) + path.addLine(to: CGPoint(x: 0.2125*width, y: 0.18*height)) + path.addCurve(to: CGPoint(x: 0.316*width, y: 0.273*height), control1: CGPoint(x: 0.2335*width, y: 0.2105*height), control2: CGPoint(x: 0.287*width, y: 0.2585*height)) + path.addCurve(to: CGPoint(x: 0.371*width, y: 0.289*height), control1: CGPoint(x: 0.331*width, y: 0.2805*height), control2: CGPoint(x: 0.354*width, y: 0.287*height)) + path.addLine(to: CGPoint(x: 0.4*width, y: 0.2915*height)) + path.addLine(to: CGPoint(x: 0.375*width, y: 0.318*height)) + path.addCurve(to: CGPoint(x: 0.3195*width, y: 0.443*height), control1: CGPoint(x: 0.3415*width, y: 0.3535*height), control2: CGPoint(x: 0.326*width, y: 0.388*height)) + path.addCurve(to: CGPoint(x: 0.2635*width, y: 0.564*height), control1: CGPoint(x: 0.3125*width, y: 0.501*height), control2: CGPoint(x: 0.302*width, y: 0.5235*height)) + path.addCurve(to: CGPoint(x: 0.19*width, y: 0.7345*height), control1: CGPoint(x: 0.21*width, y: 0.62*height), control2: CGPoint(x: 0.19*width, y: 0.6665*height)) + path.addCurve(to: CGPoint(x: 0.3235*width, y: 0.949*height), control1: CGPoint(x: 0.19*width, y: 0.8305*height), control2: CGPoint(x: 0.2385*width, y: 0.9085*height)) + path.addCurve(to: CGPoint(x: 0.4125*width, y: 0.9675*height), control1: CGPoint(x: 0.3605*width, y: 0.9665*height), control2: CGPoint(x: 0.365*width, y: 0.9675*height)) + path.addCurve(to: CGPoint(x: 0.4875*width, y: 0.958*height), control1: CGPoint(x: 0.449*width, y: 0.9675*height), control2: CGPoint(x: 0.4695*width, y: 0.965*height)) + path.addCurve(to: CGPoint(x: 0.547*width, y: 0.9595*height), control1: CGPoint(x: 0.5125*width, y: 0.949*height), control2: CGPoint(x: 0.513*width, y: 0.949*height)) + path.addCurve(to: CGPoint(x: 0.759*width, y: 0.9135*height), control1: CGPoint(x: 0.6225*width, y: 0.983*height), control2: CGPoint(x: 0.702*width, y: 0.9655*height)) + path.addCurve(to: CGPoint(x: 0.7975*width, y: 0.817*height), control1: CGPoint(x: 0.8085*width, y: 0.8675*height), control2: CGPoint(x: 0.8225*width, y: 0.8335*height)) + path.addCurve(to: CGPoint(x: 0.7615*width, y: 0.817*height), control1: CGPoint(x: 0.786*width, y: 0.8095*height), control2: CGPoint(x: 0.7835*width, y: 0.8095*height)) + path.addCurve(to: CGPoint(x: 0.661*width, y: 0.8015*height), control1: CGPoint(x: 0.723*width, y: 0.83*height), control2: CGPoint(x: 0.6935*width, y: 0.8255*height)) + path.addCurve(to: CGPoint(x: 0.634*width, y: 0.6745*height), control1: CGPoint(x: 0.6245*width, y: 0.7745*height), control2: CGPoint(x: 0.611*width, y: 0.711*height)) + path.addCurve(to: CGPoint(x: 0.6545*width, y: 0.618*height), control1: CGPoint(x: 0.659*width, y: 0.6345*height), control2: CGPoint(x: 0.6605*width, y: 0.631*height)) + path.addCurve(to: CGPoint(x: 0.6325*width, y: 0.6*height), control1: CGPoint(x: 0.651*width, y: 0.611*height), control2: CGPoint(x: 0.6415*width, y: 0.603*height)) + path.addCurve(to: CGPoint(x: 0.575*width, y: 0.5175*height), control1: CGPoint(x: 0.603*width, y: 0.59*height), control2: CGPoint(x: 0.575*width, y: 0.55*height)) + path.addCurve(to: CGPoint(x: 0.6595*width, y: 0.4255*height), control1: CGPoint(x: 0.575*width, y: 0.4685*height), control2: CGPoint(x: 0.609*width, y: 0.4315*height)) + path.addCurve(to: CGPoint(x: 0.691*width, y: 0.4095*height), control1: CGPoint(x: 0.6755*width, y: 0.4235*height), control2: CGPoint(x: 0.684*width, y: 0.419*height)) + path.addCurve(to: CGPoint(x: 0.691*width, y: 0.3745*height), control1: CGPoint(x: 0.701*width, y: 0.3965*height), control2: CGPoint(x: 0.701*width, y: 0.396*height)) + path.addCurve(to: CGPoint(x: 0.565*width, y: 0.2645*height), control1: CGPoint(x: 0.667*width, y: 0.3215*height), control2: CGPoint(x: 0.6175*width, y: 0.278*height)) + path.addLine(to: CGPoint(x: 0.54*width, y: 0.258*height)) + path.addLine(to: CGPoint(x: 0.54*width, y: 0.2355*height)) + path.addCurve(to: CGPoint(x: 0.6215*width, y: 0.102*height), control1: CGPoint(x: 0.54*width, y: 0.192*height), control2: CGPoint(x: 0.5745*width, y: 0.1355*height)) + path.addCurve(to: CGPoint(x: 0.66*width, y: 0.0575*height), control1: CGPoint(x: 0.653*width, y: 0.0795*height), control2: CGPoint(x: 0.66*width, y: 0.0715*height)) + path.addCurve(to: CGPoint(x: 0.6315*width, y: 0.03*height), control1: CGPoint(x: 0.66*width, y: 0.044*height), control2: CGPoint(x: 0.6455*width, y: 0.03*height)) + path.addCurve(to: CGPoint(x: 0.5985*width, y: 0.045*height), control1: CGPoint(x: 0.626*width, y: 0.03*height), control2: CGPoint(x: 0.6115*width, y: 0.037*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 0.4155*width, y: 0.1615*height)) + path.addCurve(to: CGPoint(x: 0.444*width, y: 0.19*height), control1: CGPoint(x: 0.4245*width, y: 0.1675*height), control2: CGPoint(x: 0.4375*width, y: 0.1805*height)) + path.addLine(to: CGPoint(x: 0.4555*width, y: 0.2075*height)) + path.addLine(to: CGPoint(x: 0.445*width, y: 0.216*height)) + path.addCurve(to: CGPoint(x: 0.369*width, y: 0.23*height), control1: CGPoint(x: 0.4265*width, y: 0.231*height), control2: CGPoint(x: 0.397*width, y: 0.2365*height)) + path.addCurve(to: CGPoint(x: 0.285*width, y: 0.175*height), control1: CGPoint(x: 0.345*width, y: 0.224*height), control2: CGPoint(x: 0.285*width, y: 0.185*height)) + path.addCurve(to: CGPoint(x: 0.2865*width, y: 0.17*height), control1: CGPoint(x: 0.285*width, y: 0.1725*height), control2: CGPoint(x: 0.2855*width, y: 0.17*height)) + path.addCurve(to: CGPoint(x: 0.315*width, y: 0.16*height), control1: CGPoint(x: 0.287*width, y: 0.17*height), control2: CGPoint(x: 0.3*width, y: 0.1655*height)) + path.addCurve(to: CGPoint(x: 0.4155*width, y: 0.1615*height), control1: CGPoint(x: 0.3535*width, y: 0.1465*height), control2: CGPoint(x: 0.394*width, y: 0.147*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 0.553*width, y: 0.3225*height)) + path.addCurve(to: CGPoint(x: 0.62*width, y: 0.369*height), control1: CGPoint(x: 0.5755*width, y: 0.329*height), control2: CGPoint(x: 0.62*width, y: 0.3605*height)) + path.addCurve(to: CGPoint(x: 0.599*width, y: 0.382*height), control1: CGPoint(x: 0.62*width, y: 0.371*height), control2: CGPoint(x: 0.6105*width, y: 0.377*height)) + path.addCurve(to: CGPoint(x: 0.5295*width, y: 0.453*height), control1: CGPoint(x: 0.572*width, y: 0.3945*height), control2: CGPoint(x: 0.5445*width, y: 0.4225*height)) + path.addCurve(to: CGPoint(x: 0.5315*width, y: 0.5815*height), control1: CGPoint(x: 0.512*width, y: 0.4895*height), control2: CGPoint(x: 0.5125*width, y: 0.5425*height)) + path.addCurve(to: CGPoint(x: 0.565*width, y: 0.626*height), control1: CGPoint(x: 0.5395*width, y: 0.597*height), control2: CGPoint(x: 0.5545*width, y: 0.6175*height)) + path.addCurve(to: CGPoint(x: 0.576*width, y: 0.6575*height), control1: CGPoint(x: 0.584*width, y: 0.642*height), control2: CGPoint(x: 0.584*width, y: 0.6425*height)) + path.addCurve(to: CGPoint(x: 0.572*width, y: 0.7725*height), control1: CGPoint(x: 0.5645*width, y: 0.68*height), control2: CGPoint(x: 0.562*width, y: 0.744*height)) + path.addCurve(to: CGPoint(x: 0.6785*width, y: 0.8755*height), control1: CGPoint(x: 0.5875*width, y: 0.8195*height), control2: CGPoint(x: 0.632*width, y: 0.862*height)) + path.addCurve(to: CGPoint(x: 0.6665*width, y: 0.902*height), control1: CGPoint(x: 0.7045*width, y: 0.883*height), control2: CGPoint(x: 0.701*width, y: 0.8905*height)) + path.addCurve(to: CGPoint(x: 0.546*width, y: 0.897*height), control1: CGPoint(x: 0.6305*width, y: 0.9145*height), control2: CGPoint(x: 0.585*width, y: 0.9125*height)) + path.addCurve(to: CGPoint(x: 0.498*width, y: 0.89*height), control1: CGPoint(x: 0.517*width, y: 0.885*height), control2: CGPoint(x: 0.5115*width, y: 0.8845*height)) + path.addCurve(to: CGPoint(x: 0.405*width, y: 0.909*height), control1: CGPoint(x: 0.451*width, y: 0.909*height), control2: CGPoint(x: 0.4415*width, y: 0.911*height)) + path.addCurve(to: CGPoint(x: 0.2925*width, y: 0.8535*height), control1: CGPoint(x: 0.3585*width, y: 0.9065*height), control2: CGPoint(x: 0.3245*width, y: 0.8895*height)) + path.addCurve(to: CGPoint(x: 0.2485*width, y: 0.734*height), control1: CGPoint(x: 0.2625*width, y: 0.8205*height), control2: CGPoint(x: 0.2485*width, y: 0.7825*height)) + path.addCurve(to: CGPoint(x: 0.3115*width, y: 0.597*height), control1: CGPoint(x: 0.2485*width, y: 0.6825*height), control2: CGPoint(x: 0.267*width, y: 0.642*height)) + path.addCurve(to: CGPoint(x: 0.375*width, y: 0.465*height), control1: CGPoint(x: 0.3535*width, y: 0.5545*height), control2: CGPoint(x: 0.3695*width, y: 0.5215*height)) + path.addCurve(to: CGPoint(x: 0.385*width, y: 0.4075*height), control1: CGPoint(x: 0.3775*width, y: 0.441*height), control2: CGPoint(x: 0.382*width, y: 0.415*height)) + path.addCurve(to: CGPoint(x: 0.438*width, y: 0.3395*height), control1: CGPoint(x: 0.394*width, y: 0.3835*height), control2: CGPoint(x: 0.4195*width, y: 0.351*height)) + path.addCurve(to: CGPoint(x: 0.553*width, y: 0.3225*height), control1: CGPoint(x: 0.4785*width, y: 0.3145*height), control2: CGPoint(x: 0.5105*width, y: 0.31*height)) + path.closeSubpath() + return path + } +} + +// Pear text +struct Pearcleaner: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + let width = rect.size.width + let height = rect.size.height + path.move(to: CGPoint(x: 1.10767*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.10292*width, y: -0.22248*height), control1: CGPoint(x: 1.10519*width, y: -0.23943*height), control2: CGPoint(x: 1.10375*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.09362*width, y: -0.14302*height), control1: CGPoint(x: 1.10044*width, y: -0.1854*height), control2: CGPoint(x: 1.09755*width, y: -0.16315*height)) + path.addCurve(to: CGPoint(x: 1.0744*width, y: -0.09005*height), control1: CGPoint(x: 1.08783*width, y: -0.11442*height), control2: CGPoint(x: 1.07977*width, y: -0.09005*height)) + path.addCurve(to: CGPoint(x: 1.09052*width, y: -0.24684*height), control1: CGPoint(x: 1.07977*width, y: -0.10594*height), control2: CGPoint(x: 1.08928*width, y: -0.16103*height)) + path.addCurve(to: CGPoint(x: 1.05869*width, y: -0.43648*height), control1: CGPoint(x: 1.09217*width, y: -0.36126*height), control2: CGPoint(x: 1.0775*width, y: -0.43648*height)) + path.addCurve(to: CGPoint(x: 1.02955*width, y: -0.36868*height), control1: CGPoint(x: 1.04546*width, y: -0.43648*height), control2: CGPoint(x: 1.03513*width, y: -0.39834*height)) + path.addLine(to: CGPoint(x: 1.03058*width, y: -0.40364*height)) + path.addCurve(to: CGPoint(x: 1.02686*width, y: -0.42377*height), control1: CGPoint(x: 1.031*width, y: -0.41529*height), control2: CGPoint(x: 1.02934*width, y: -0.42377*height)) + path.addLine(to: CGPoint(x: 1.01054*width, y: -0.42377*height)) + path.addCurve(to: CGPoint(x: 1.00578*width, y: -0.40258*height), control1: CGPoint(x: 1.00805*width, y: -0.42377*height), control2: CGPoint(x: 1.00619*width, y: -0.41529*height)) + path.addLine(to: CGPoint(x: 0.98532*width, y: 0.26062*height)) + path.addCurve(to: CGPoint(x: 0.98883*width, y: 0.2818*height), control1: CGPoint(x: 0.98491*width, y: 0.27227*height), control2: CGPoint(x: 0.98656*width, y: 0.2818*height)) + path.addLine(to: CGPoint(x: 1.00516*width, y: 0.2818*height)) + path.addCurve(to: CGPoint(x: 1.01012*width, y: 0.25956*height), control1: CGPoint(x: 1.00805*width, y: 0.2818*height), control2: CGPoint(x: 1.00971*width, y: 0.27333*height)) + path.addLine(to: CGPoint(x: 1.02087*width, y: -0.09111*height)) + path.addCurve(to: CGPoint(x: 1.05146*width, y: -0.31888*height), control1: CGPoint(x: 1.02583*width, y: -0.2532*height), control2: CGPoint(x: 1.03926*width, y: -0.31888*height)) + path.addCurve(to: CGPoint(x: 1.06282*width, y: -0.20023*height), control1: CGPoint(x: 1.06262*width, y: -0.31888*height), control2: CGPoint(x: 1.06572*width, y: -0.26379*height)) + path.addCurve(to: CGPoint(x: 1.04298*width, y: -0.09429*height), control1: CGPoint(x: 1.06034*width, y: -0.14302*height), control2: CGPoint(x: 1.05352*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.02976*width, y: -0.09111*height), control1: CGPoint(x: 1.03203*width, y: -0.10594*height), control2: CGPoint(x: 1.03058*width, y: -0.1017*height)) + path.addLine(to: CGPoint(x: 1.02562*width, y: -0.04132*height)) + path.addCurve(to: CGPoint(x: 1.03017*width, y: -0.00848*height), control1: CGPoint(x: 1.02438*width, y: -0.02649*height), control2: CGPoint(x: 1.02542*width, y: -0.01801*height)) + path.addCurve(to: CGPoint(x: 1.05538*width, y: 0.01271*height), control1: CGPoint(x: 1.03348*width, y: -0.00106*height), control2: CGPoint(x: 1.04154*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.11801*width, y: -0.19917*height), control1: CGPoint(x: 1.08411*width, y: 0.01271*height), control2: CGPoint(x: 1.10891*width, y: -0.05615*height)) + path.addCurve(to: CGPoint(x: 1.11573*width, y: -0.22248*height), control1: CGPoint(x: 1.11883*width, y: -0.21188*height), control2: CGPoint(x: 1.1178*width, y: -0.2193*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.18208*width, y: -0.214*height)) + path.addCurve(to: CGPoint(x: 1.14695*width, y: -0.09641*height), control1: CGPoint(x: 1.17423*width, y: -0.13137*height), control2: CGPoint(x: 1.15956*width, y: -0.09641*height)) + path.addCurve(to: CGPoint(x: 1.12959*width, y: -0.14302*height), control1: CGPoint(x: 1.13806*width, y: -0.09641*height), control2: CGPoint(x: 1.13248*width, y: -0.11442*height)) + path.addCurve(to: CGPoint(x: 1.17712*width, y: -0.28604*height), control1: CGPoint(x: 1.14757*width, y: -0.1409*height), control2: CGPoint(x: 1.17237*width, y: -0.18434*height)) + path.addCurve(to: CGPoint(x: 1.14984*width, y: -0.43648*height), control1: CGPoint(x: 1.18126*width, y: -0.37186*height), control2: CGPoint(x: 1.16844*width, y: -0.43648*height)) + path.addCurve(to: CGPoint(x: 1.10148*width, y: -0.23095*height), control1: CGPoint(x: 1.12918*width, y: -0.43648*height), control2: CGPoint(x: 1.10644*width, y: -0.35702*height)) + path.addCurve(to: CGPoint(x: 1.1424*width, y: 0.01271*height), control1: CGPoint(x: 1.0959*width, y: -0.09323*height), control2: CGPoint(x: 1.11533*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.198*width, y: -0.19917*height), control1: CGPoint(x: 1.16824*width, y: 0.01271*height), control2: CGPoint(x: 1.18973*width, y: -0.08263*height)) + path.addCurve(to: CGPoint(x: 1.19573*width, y: -0.22248*height), control1: CGPoint(x: 1.19883*width, y: -0.21082*height), control2: CGPoint(x: 1.19821*width, y: -0.21824*height)) + path.addLine(to: CGPoint(x: 1.18766*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.18208*width, y: -0.214*height), control1: CGPoint(x: 1.18518*width, y: -0.23943*height), control2: CGPoint(x: 1.18415*width, y: -0.23519*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.12773*width, y: -0.20659*height)) + path.addCurve(to: CGPoint(x: 1.12794*width, y: -0.214*height), control1: CGPoint(x: 1.12773*width, y: -0.20871*height), control2: CGPoint(x: 1.12794*width, y: -0.21188*height)) + path.addCurve(to: CGPoint(x: 1.14922*width, y: -0.32736*height), control1: CGPoint(x: 1.13021*width, y: -0.27863*height), control2: CGPoint(x: 1.14137*width, y: -0.32736*height)) + path.addCurve(to: CGPoint(x: 1.15563*width, y: -0.2977*height), control1: CGPoint(x: 1.15336*width, y: -0.32736*height), control2: CGPoint(x: 1.15563*width, y: -0.31465*height)) + path.addCurve(to: CGPoint(x: 1.12773*width, y: -0.20659*height), control1: CGPoint(x: 1.15563*width, y: -0.25426*height), control2: CGPoint(x: 1.14178*width, y: -0.20976*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.21075*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.24237*width, y: -0.0678*height), control1: CGPoint(x: 1.22604*width, y: 0.01271*height), control2: CGPoint(x: 1.23782*width, y: -0.0339*height)) + path.addCurve(to: CGPoint(x: 1.26552*width, y: 0.01271*height), control1: CGPoint(x: 1.24547*width, y: -0.01907*height), control2: CGPoint(x: 1.25373*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.30644*width, y: -0.19917*height), control1: CGPoint(x: 1.28866*width, y: 0.01271*height), control2: CGPoint(x: 1.30189*width, y: -0.11018*height)) + path.addCurve(to: CGPoint(x: 1.30416*width, y: -0.22248*height), control1: CGPoint(x: 1.30706*width, y: -0.21082*height), control2: CGPoint(x: 1.30664*width, y: -0.21824*height)) + path.addLine(to: CGPoint(x: 1.2961*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.29135*width, y: -0.22248*height), control1: CGPoint(x: 1.29362*width, y: -0.23943*height), control2: CGPoint(x: 1.29218*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.27192*width, y: -0.09429*height), control1: CGPoint(x: 1.28846*width, y: -0.18328*height), control2: CGPoint(x: 1.28143*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.26717*width, y: -0.18434*height), control1: CGPoint(x: 1.26614*width, y: -0.09429*height), control2: CGPoint(x: 1.26552*width, y: -0.12819*height)) + path.addLine(to: CGPoint(x: 1.27378*width, y: -0.40258*height)) + path.addCurve(to: CGPoint(x: 1.27027*width, y: -0.42377*height), control1: CGPoint(x: 1.2742*width, y: -0.41423*height), control2: CGPoint(x: 1.27275*width, y: -0.42377*height)) + path.addLine(to: CGPoint(x: 1.25373*width, y: -0.42377*height)) + path.addCurve(to: CGPoint(x: 1.24898*width, y: -0.40258*height), control1: CGPoint(x: 1.25125*width, y: -0.42377*height), control2: CGPoint(x: 1.24939*width, y: -0.41529*height)) + path.addLine(to: CGPoint(x: 1.24877*width, y: -0.39622*height)) + path.addCurve(to: CGPoint(x: 1.22769*width, y: -0.43648*height), control1: CGPoint(x: 1.24547*width, y: -0.41105*height), control2: CGPoint(x: 1.23885*width, y: -0.43648*height)) + path.addCurve(to: CGPoint(x: 1.18264*width, y: -0.24473*height), control1: CGPoint(x: 1.20765*width, y: -0.43648*height), control2: CGPoint(x: 1.18925*width, y: -0.35596*height)) + path.addCurve(to: CGPoint(x: 1.21075*width, y: 0.01271*height), control1: CGPoint(x: 1.1752*width, y: -0.11865*height), control2: CGPoint(x: 1.18512*width, y: 0.01271*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.24567*width, y: -0.29346*height)) + path.addCurve(to: CGPoint(x: 1.21901*width, y: -0.09429*height), control1: CGPoint(x: 1.24278*width, y: -0.18858*height), control2: CGPoint(x: 1.23183*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.20806*width, y: -0.21294*height), control1: CGPoint(x: 1.2093*width, y: -0.09429*height), control2: CGPoint(x: 1.20496*width, y: -0.15044*height)) + path.addCurve(to: CGPoint(x: 1.23245*width, y: -0.3263*height), control1: CGPoint(x: 1.21178*width, y: -0.28604*height), control2: CGPoint(x: 1.22232*width, y: -0.3263*height)) + path.addCurve(to: CGPoint(x: 1.24567*width, y: -0.29346*height), control1: CGPoint(x: 1.23968*width, y: -0.3263*height), control2: CGPoint(x: 1.24361*width, y: -0.30511*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.36936*width, y: -0.22248*height)) + path.addCurve(to: CGPoint(x: 1.34807*width, y: -0.09429*height), control1: CGPoint(x: 1.36626*width, y: -0.17904*height), control2: CGPoint(x: 1.35799*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.34228*width, y: -0.16527*height), control1: CGPoint(x: 1.34331*width, y: -0.09429*height), control2: CGPoint(x: 1.34001*width, y: -0.11442*height)) + path.addCurve(to: CGPoint(x: 1.34972*width, y: -0.31253*height), control1: CGPoint(x: 1.34497*width, y: -0.22777*height), control2: CGPoint(x: 1.34931*width, y: -0.30405*height)) + path.addCurve(to: CGPoint(x: 1.34393*width, y: -0.38245*height), control1: CGPoint(x: 1.35117*width, y: -0.34749*height), control2: CGPoint(x: 1.35075*width, y: -0.36656*height)) + path.addCurve(to: CGPoint(x: 1.315*width, y: -0.44813*height), control1: CGPoint(x: 1.3336*width, y: -0.40576*height), control2: CGPoint(x: 1.32099*width, y: -0.42589*height)) + path.addCurve(to: CGPoint(x: 1.30322*width, y: -0.52017*height), control1: CGPoint(x: 1.31541*width, y: -0.48945*height), control2: CGPoint(x: 1.31128*width, y: -0.52441*height)) + path.addCurve(to: CGPoint(x: 1.29495*width, y: -0.40258*height), control1: CGPoint(x: 1.29392*width, y: -0.51594*height), control2: CGPoint(x: 1.28999*width, y: -0.46508*height)) + path.addCurve(to: CGPoint(x: 1.29061*width, y: -0.21506*height), control1: CGPoint(x: 1.29619*width, y: -0.3655*height), control2: CGPoint(x: 1.29537*width, y: -0.27969*height)) + path.addCurve(to: CGPoint(x: 1.29206*width, y: -0.19493*height), control1: CGPoint(x: 1.28979*width, y: -0.20553*height), control2: CGPoint(x: 1.2902*width, y: -0.19811*height)) + path.addLine(to: CGPoint(x: 1.30177*width, y: -0.17586*height)) + path.addCurve(to: CGPoint(x: 1.30549*width, y: -0.18434*height), control1: CGPoint(x: 1.30363*width, y: -0.17268*height), control2: CGPoint(x: 1.30487*width, y: -0.17374*height)) + path.addCurve(to: CGPoint(x: 1.31211*width, y: -0.35279*height), control1: CGPoint(x: 1.30859*width, y: -0.23519*height), control2: CGPoint(x: 1.31087*width, y: -0.29346*height)) + path.addLine(to: CGPoint(x: 1.32017*width, y: -0.33372*height)) + path.addCurve(to: CGPoint(x: 1.32347*width, y: -0.29664*height), control1: CGPoint(x: 1.32347*width, y: -0.3263*height), control2: CGPoint(x: 1.32451*width, y: -0.31783*height)) + path.addCurve(to: CGPoint(x: 1.31583*width, y: -0.14408*height), control1: CGPoint(x: 1.32079*width, y: -0.23625*height), control2: CGPoint(x: 1.31748*width, y: -0.19387*height)) + path.addCurve(to: CGPoint(x: 1.3429*width, y: 0.01271*height), control1: CGPoint(x: 1.31335*width, y: -0.06145*height), control2: CGPoint(x: 1.32554*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.38444*width, y: -0.19917*height), control1: CGPoint(x: 1.36543*width, y: 0.01271*height), control2: CGPoint(x: 1.3799*width, y: -0.11018*height)) + path.addCurve(to: CGPoint(x: 1.38217*width, y: -0.22248*height), control1: CGPoint(x: 1.38506*width, y: -0.21082*height), control2: CGPoint(x: 1.38465*width, y: -0.21824*height)) + path.addLine(to: CGPoint(x: 1.37411*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.36936*width, y: -0.22248*height), control1: CGPoint(x: 1.37163*width, y: -0.23943*height), control2: CGPoint(x: 1.37018*width, y: -0.23519*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.45862*width, y: -0.22248*height)) + path.addLine(to: CGPoint(x: 1.45056*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.44539*width, y: -0.21824*height), control1: CGPoint(x: 1.44787*width, y: -0.23943*height), control2: CGPoint(x: 1.44705*width, y: -0.23413*height)) + path.addCurve(to: CGPoint(x: 1.41253*width, y: -0.09429*height), control1: CGPoint(x: 1.4363*width, y: -0.13666*height), control2: CGPoint(x: 1.42514*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.39455*width, y: -0.22036*height), control1: CGPoint(x: 1.39703*width, y: -0.09429*height), control2: CGPoint(x: 1.39166*width, y: -0.15573*height)) + path.addCurve(to: CGPoint(x: 1.41956*width, y: -0.32948*height), control1: CGPoint(x: 1.39744*width, y: -0.28498*height), control2: CGPoint(x: 1.40778*width, y: -0.32948*height)) + path.addCurve(to: CGPoint(x: 1.42968*width, y: -0.31783*height), control1: CGPoint(x: 1.42348*width, y: -0.32948*height), control2: CGPoint(x: 1.427*width, y: -0.32418*height)) + path.addCurve(to: CGPoint(x: 1.43506*width, y: -0.32312*height), control1: CGPoint(x: 1.43216*width, y: -0.31253*height), control2: CGPoint(x: 1.4332*width, y: -0.31253*height)) + path.addLine(to: CGPoint(x: 1.44126*width, y: -0.3602*height)) + path.addCurve(to: CGPoint(x: 1.44043*width, y: -0.38987*height), control1: CGPoint(x: 1.44271*width, y: -0.36974*height), control2: CGPoint(x: 1.44312*width, y: -0.37609*height)) + path.addCurve(to: CGPoint(x: 1.4148*width, y: -0.43648*height), control1: CGPoint(x: 1.43568*width, y: -0.41211*height), control2: CGPoint(x: 1.42576*width, y: -0.43648*height)) + path.addCurve(to: CGPoint(x: 1.36768*width, y: -0.2246*height), control1: CGPoint(x: 1.39455*width, y: -0.43648*height), control2: CGPoint(x: 1.37202*width, y: -0.3549*height)) + path.addCurve(to: CGPoint(x: 1.40592*width, y: 0.01271*height), control1: CGPoint(x: 1.36355*width, y: -0.09535*height), control2: CGPoint(x: 1.37926*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.46089*width, y: -0.19917*height), control1: CGPoint(x: 1.42968*width, y: 0.01271*height), control2: CGPoint(x: 1.45139*width, y: -0.0731*height)) + path.addCurve(to: CGPoint(x: 1.45862*width, y: -0.22248*height), control1: CGPoint(x: 1.46172*width, y: -0.21082*height), control2: CGPoint(x: 1.4611*width, y: -0.21824*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.52396*width, y: -0.22354*height)) + path.addLine(to: CGPoint(x: 1.5159*width, y: -0.23625*height)) + path.addCurve(to: CGPoint(x: 1.51114*width, y: -0.22566*height), control1: CGPoint(x: 1.51362*width, y: -0.23943*height), control2: CGPoint(x: 1.51218*width, y: -0.23731*height)) + path.addCurve(to: CGPoint(x: 1.48428*width, y: -0.09641*height), control1: CGPoint(x: 1.50164*width, y: -0.12395*height), control2: CGPoint(x: 1.4911*width, y: -0.09641*height)) + path.addCurve(to: CGPoint(x: 1.46692*width, y: -0.25214*height), control1: CGPoint(x: 1.47312*width, y: -0.09641*height), control2: CGPoint(x: 1.46754*width, y: -0.17374*height)) + path.addCurve(to: CGPoint(x: 1.51301*width, y: -0.44284*height), control1: CGPoint(x: 1.48325*width, y: -0.27333*height), control2: CGPoint(x: 1.50267*width, y: -0.33372*height)) + path.addCurve(to: CGPoint(x: 1.49813*width, y: -0.70133*height), control1: CGPoint(x: 1.52231*width, y: -0.54242*height), control2: CGPoint(x: 1.52603*width, y: -0.70133*height)) + path.addCurve(to: CGPoint(x: 1.44584*width, y: -0.36762*height), control1: CGPoint(x: 1.47705*width, y: -0.70133*height), control2: CGPoint(x: 1.45452*width, y: -0.57314*height)) + path.addCurve(to: CGPoint(x: 1.47829*width, y: 0.01271*height), control1: CGPoint(x: 1.43922*width, y: -0.21188*height), control2: CGPoint(x: 1.44294*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.52499*width, y: -0.18964*height), control1: CGPoint(x: 1.49854*width, y: 0.01271*height), control2: CGPoint(x: 1.51569*width, y: -0.06145*height)) + path.addCurve(to: CGPoint(x: 1.52396*width, y: -0.22354*height), control1: CGPoint(x: 1.52665*width, y: -0.21082*height), control2: CGPoint(x: 1.52685*width, y: -0.21824*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.46878*width, y: -0.34961*height)) + path.addCurve(to: CGPoint(x: 1.49523*width, y: -0.59221*height), control1: CGPoint(x: 1.47394*width, y: -0.47462*height), control2: CGPoint(x: 1.488*width, y: -0.5901*height)) + path.addCurve(to: CGPoint(x: 1.49296*width, y: -0.46508*height), control1: CGPoint(x: 1.5006*width, y: -0.59327*height), control2: CGPoint(x: 1.49957*width, y: -0.52759*height)) + path.addCurve(to: CGPoint(x: 1.46878*width, y: -0.34961*height), control1: CGPoint(x: 1.48655*width, y: -0.40258*height), control2: CGPoint(x: 1.47684*width, y: -0.36444*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.58615*width, y: -0.214*height)) + path.addCurve(to: CGPoint(x: 1.55101*width, y: -0.09641*height), control1: CGPoint(x: 1.5783*width, y: -0.13137*height), control2: CGPoint(x: 1.56362*width, y: -0.09641*height)) + path.addCurve(to: CGPoint(x: 1.53366*width, y: -0.14302*height), control1: CGPoint(x: 1.54213*width, y: -0.09641*height), control2: CGPoint(x: 1.53655*width, y: -0.11442*height)) + path.addCurve(to: CGPoint(x: 1.58119*width, y: -0.28604*height), control1: CGPoint(x: 1.55164*width, y: -0.1409*height), control2: CGPoint(x: 1.57644*width, y: -0.18434*height)) + path.addCurve(to: CGPoint(x: 1.55391*width, y: -0.43648*height), control1: CGPoint(x: 1.58533*width, y: -0.37186*height), control2: CGPoint(x: 1.57251*width, y: -0.43648*height)) + path.addCurve(to: CGPoint(x: 1.50555*width, y: -0.23095*height), control1: CGPoint(x: 1.53324*width, y: -0.43648*height), control2: CGPoint(x: 1.51051*width, y: -0.35702*height)) + path.addCurve(to: CGPoint(x: 1.54647*width, y: 0.01271*height), control1: CGPoint(x: 1.49997*width, y: -0.09323*height), control2: CGPoint(x: 1.5194*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.60207*width, y: -0.19917*height), control1: CGPoint(x: 1.57231*width, y: 0.01271*height), control2: CGPoint(x: 1.5938*width, y: -0.08263*height)) + path.addCurve(to: CGPoint(x: 1.59979*width, y: -0.22248*height), control1: CGPoint(x: 1.60289*width, y: -0.21082*height), control2: CGPoint(x: 1.60227*width, y: -0.21824*height)) + path.addLine(to: CGPoint(x: 1.59173*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.58615*width, y: -0.214*height), control1: CGPoint(x: 1.58925*width, y: -0.23943*height), control2: CGPoint(x: 1.58822*width, y: -0.23519*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.5318*width, y: -0.20659*height)) + path.addCurve(to: CGPoint(x: 1.532*width, y: -0.214*height), control1: CGPoint(x: 1.5318*width, y: -0.20871*height), control2: CGPoint(x: 1.532*width, y: -0.21188*height)) + path.addCurve(to: CGPoint(x: 1.55329*width, y: -0.32736*height), control1: CGPoint(x: 1.53428*width, y: -0.27863*height), control2: CGPoint(x: 1.54544*width, y: -0.32736*height)) + path.addCurve(to: CGPoint(x: 1.5597*width, y: -0.2977*height), control1: CGPoint(x: 1.55742*width, y: -0.32736*height), control2: CGPoint(x: 1.5597*width, y: -0.31465*height)) + path.addCurve(to: CGPoint(x: 1.5318*width, y: -0.20659*height), control1: CGPoint(x: 1.5597*width, y: -0.25426*height), control2: CGPoint(x: 1.54585*width, y: -0.20976*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.61481*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.64643*width, y: -0.0678*height), control1: CGPoint(x: 1.63011*width, y: 0.01271*height), control2: CGPoint(x: 1.64189*width, y: -0.0339*height)) + path.addCurve(to: CGPoint(x: 1.66958*width, y: 0.01271*height), control1: CGPoint(x: 1.64953*width, y: -0.01907*height), control2: CGPoint(x: 1.6578*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.7105*width, y: -0.19917*height), control1: CGPoint(x: 1.69273*width, y: 0.01271*height), control2: CGPoint(x: 1.70596*width, y: -0.11018*height)) + path.addCurve(to: CGPoint(x: 1.70823*width, y: -0.22248*height), control1: CGPoint(x: 1.71112*width, y: -0.21082*height), control2: CGPoint(x: 1.71071*width, y: -0.21824*height)) + path.addLine(to: CGPoint(x: 1.70017*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.69542*width, y: -0.22248*height), control1: CGPoint(x: 1.69769*width, y: -0.23943*height), control2: CGPoint(x: 1.69624*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.67599*width, y: -0.09429*height), control1: CGPoint(x: 1.69252*width, y: -0.18328*height), control2: CGPoint(x: 1.68549*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.67123*width, y: -0.18434*height), control1: CGPoint(x: 1.6702*width, y: -0.09429*height), control2: CGPoint(x: 1.66958*width, y: -0.12819*height)) + path.addLine(to: CGPoint(x: 1.67785*width, y: -0.40258*height)) + path.addCurve(to: CGPoint(x: 1.67433*width, y: -0.42377*height), control1: CGPoint(x: 1.67826*width, y: -0.41423*height), control2: CGPoint(x: 1.67681*width, y: -0.42377*height)) + path.addLine(to: CGPoint(x: 1.6578*width, y: -0.42377*height)) + path.addCurve(to: CGPoint(x: 1.65305*width, y: -0.40258*height), control1: CGPoint(x: 1.65532*width, y: -0.42377*height), control2: CGPoint(x: 1.65346*width, y: -0.41529*height)) + path.addLine(to: CGPoint(x: 1.65284*width, y: -0.39622*height)) + path.addCurve(to: CGPoint(x: 1.63176*width, y: -0.43648*height), control1: CGPoint(x: 1.64953*width, y: -0.41105*height), control2: CGPoint(x: 1.64292*width, y: -0.43648*height)) + path.addCurve(to: CGPoint(x: 1.5867*width, y: -0.24473*height), control1: CGPoint(x: 1.61171*width, y: -0.43648*height), control2: CGPoint(x: 1.59332*width, y: -0.35596*height)) + path.addCurve(to: CGPoint(x: 1.61481*width, y: 0.01271*height), control1: CGPoint(x: 1.57926*width, y: -0.11865*height), control2: CGPoint(x: 1.58918*width, y: 0.01271*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.64974*width, y: -0.29346*height)) + path.addCurve(to: CGPoint(x: 1.62308*width, y: -0.09429*height), control1: CGPoint(x: 1.64685*width, y: -0.18858*height), control2: CGPoint(x: 1.63589*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.61212*width, y: -0.21294*height), control1: CGPoint(x: 1.61336*width, y: -0.09429*height), control2: CGPoint(x: 1.60902*width, y: -0.15044*height)) + path.addCurve(to: CGPoint(x: 1.63651*width, y: -0.3263*height), control1: CGPoint(x: 1.61585*width, y: -0.28604*height), control2: CGPoint(x: 1.62639*width, y: -0.3263*height)) + path.addCurve(to: CGPoint(x: 1.64974*width, y: -0.29346*height), control1: CGPoint(x: 1.64375*width, y: -0.3263*height), control2: CGPoint(x: 1.64767*width, y: -0.30511*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.68931*width, y: -0.02119*height)) + path.addCurve(to: CGPoint(x: 1.69282*width, y: 0), control1: CGPoint(x: 1.6891*width, y: -0.00953*height), control2: CGPoint(x: 1.69055*width, y: 0)) + path.addLine(to: CGPoint(x: 1.70935*width, y: 0)) + path.addCurve(to: CGPoint(x: 1.71411*width, y: -0.02119*height), control1: CGPoint(x: 1.71225*width, y: 0), control2: CGPoint(x: 1.71369*width, y: -0.00848*height)) + path.addLine(to: CGPoint(x: 1.71597*width, y: -0.08263*height)) + path.addCurve(to: CGPoint(x: 1.74366*width, y: -0.31677*height), control1: CGPoint(x: 1.71886*width, y: -0.17798*height), control2: CGPoint(x: 1.73292*width, y: -0.31677*height)) + path.addCurve(to: CGPoint(x: 1.748*width, y: -0.2532*height), control1: CGPoint(x: 1.74821*width, y: -0.31677*height), control2: CGPoint(x: 1.74924*width, y: -0.29346*height)) + path.addLine(to: CGPoint(x: 1.7447*width, y: -0.14832*height)) + path.addCurve(to: CGPoint(x: 1.76888*width, y: 0.01271*height), control1: CGPoint(x: 1.74201*width, y: -0.05933*height), control2: CGPoint(x: 1.7511*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.8098*width, y: -0.19917*height), control1: CGPoint(x: 1.79202*width, y: 0.01271*height), control2: CGPoint(x: 1.80525*width, y: -0.11018*height)) + path.addCurve(to: CGPoint(x: 1.80753*width, y: -0.22248*height), control1: CGPoint(x: 1.81042*width, y: -0.21082*height), control2: CGPoint(x: 1.81001*width, y: -0.21824*height)) + path.addLine(to: CGPoint(x: 1.79946*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.79471*width, y: -0.22248*height), control1: CGPoint(x: 1.79698*width, y: -0.23943*height), control2: CGPoint(x: 1.79574*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.77528*width, y: -0.09429*height), control1: CGPoint(x: 1.79161*width, y: -0.18328*height), control2: CGPoint(x: 1.78479*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.77053*width, y: -0.18434*height), control1: CGPoint(x: 1.7695*width, y: -0.09429*height), control2: CGPoint(x: 1.76888*width, y: -0.12819*height)) + path.addLine(to: CGPoint(x: 1.7728*width, y: -0.26274*height)) + path.addCurve(to: CGPoint(x: 1.75358*width, y: -0.43648*height), control1: CGPoint(x: 1.7759*width, y: -0.35914*height), control2: CGPoint(x: 1.77032*width, y: -0.43648*height)) + path.addCurve(to: CGPoint(x: 1.72403*width, y: -0.34749*height), control1: CGPoint(x: 1.74056*width, y: -0.43648*height), control2: CGPoint(x: 1.73044*width, y: -0.39092*height)) + path.addLine(to: CGPoint(x: 1.72568*width, y: -0.40258*height)) + path.addCurve(to: CGPoint(x: 1.72217*width, y: -0.42377*height), control1: CGPoint(x: 1.7261*width, y: -0.41423*height), control2: CGPoint(x: 1.72465*width, y: -0.42377*height)) + path.addLine(to: CGPoint(x: 1.70584*width, y: -0.42377*height)) + path.addCurve(to: CGPoint(x: 1.70109*width, y: -0.40258*height), control1: CGPoint(x: 1.70336*width, y: -0.42377*height), control2: CGPoint(x: 1.7015*width, y: -0.41529*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.87397*width, y: -0.214*height)) + path.addCurve(to: CGPoint(x: 1.83883*width, y: -0.09641*height), control1: CGPoint(x: 1.86611*width, y: -0.13137*height), control2: CGPoint(x: 1.85144*width, y: -0.09641*height)) + path.addCurve(to: CGPoint(x: 1.82147*width, y: -0.14302*height), control1: CGPoint(x: 1.82994*width, y: -0.09641*height), control2: CGPoint(x: 1.82436*width, y: -0.11442*height)) + path.addCurve(to: CGPoint(x: 1.86901*width, y: -0.28604*height), control1: CGPoint(x: 1.83945*width, y: -0.1409*height), control2: CGPoint(x: 1.86425*width, y: -0.18434*height)) + path.addCurve(to: CGPoint(x: 1.84172*width, y: -0.43648*height), control1: CGPoint(x: 1.87314*width, y: -0.37186*height), control2: CGPoint(x: 1.86032*width, y: -0.43648*height)) + path.addCurve(to: CGPoint(x: 1.79336*width, y: -0.23095*height), control1: CGPoint(x: 1.82105*width, y: -0.43648*height), control2: CGPoint(x: 1.79832*width, y: -0.35702*height)) + path.addCurve(to: CGPoint(x: 1.83428*width, y: 0.01271*height), control1: CGPoint(x: 1.78778*width, y: -0.09323*height), control2: CGPoint(x: 1.80721*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.88988*width, y: -0.19917*height), control1: CGPoint(x: 1.86012*width, y: 0.01271*height), control2: CGPoint(x: 1.88161*width, y: -0.08263*height)) + path.addCurve(to: CGPoint(x: 1.8876*width, y: -0.22248*height), control1: CGPoint(x: 1.8907*width, y: -0.21082*height), control2: CGPoint(x: 1.89008*width, y: -0.21824*height)) + path.addLine(to: CGPoint(x: 1.87954*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.87396*width, y: -0.214*height), control1: CGPoint(x: 1.87706*width, y: -0.23943*height), control2: CGPoint(x: 1.87603*width, y: -0.23519*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.81961*width, y: -0.20659*height)) + path.addCurve(to: CGPoint(x: 1.81982*width, y: -0.214*height), control1: CGPoint(x: 1.81961*width, y: -0.20871*height), control2: CGPoint(x: 1.81982*width, y: -0.21188*height)) + path.addCurve(to: CGPoint(x: 1.8411*width, y: -0.32736*height), control1: CGPoint(x: 1.82209*width, y: -0.27863*height), control2: CGPoint(x: 1.83325*width, y: -0.32736*height)) + path.addCurve(to: CGPoint(x: 1.84751*width, y: -0.2977*height), control1: CGPoint(x: 1.84524*width, y: -0.32736*height), control2: CGPoint(x: 1.84751*width, y: -0.31465*height)) + path.addCurve(to: CGPoint(x: 1.81961*width, y: -0.20659*height), control1: CGPoint(x: 1.84751*width, y: -0.25426*height), control2: CGPoint(x: 1.83366*width, y: -0.20976*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 1.95305*width, y: -0.22248*height)) + path.addCurve(to: CGPoint(x: 1.93177*width, y: -0.09429*height), control1: CGPoint(x: 1.94995*width, y: -0.17904*height), control2: CGPoint(x: 1.94169*width, y: -0.09429*height)) + path.addCurve(to: CGPoint(x: 1.92598*width, y: -0.16527*height), control1: CGPoint(x: 1.92701*width, y: -0.09429*height), control2: CGPoint(x: 1.92371*width, y: -0.11442*height)) + path.addCurve(to: CGPoint(x: 1.93342*width, y: -0.31253*height), control1: CGPoint(x: 1.92867*width, y: -0.22777*height), control2: CGPoint(x: 1.93301*width, y: -0.30405*height)) + path.addCurve(to: CGPoint(x: 1.92763*width, y: -0.38245*height), control1: CGPoint(x: 1.93487*width, y: -0.34749*height), control2: CGPoint(x: 1.93445*width, y: -0.36656*height)) + path.addCurve(to: CGPoint(x: 1.8987*width, y: -0.44813*height), control1: CGPoint(x: 1.9173*width, y: -0.40576*height), control2: CGPoint(x: 1.90469*width, y: -0.42589*height)) + path.addCurve(to: CGPoint(x: 1.88692*width, y: -0.52017*height), control1: CGPoint(x: 1.89911*width, y: -0.48945*height), control2: CGPoint(x: 1.89498*width, y: -0.52441*height)) + path.addCurve(to: CGPoint(x: 1.87865*width, y: -0.40258*height), control1: CGPoint(x: 1.87762*width, y: -0.51594*height), control2: CGPoint(x: 1.87369*width, y: -0.46508*height)) + path.addCurve(to: CGPoint(x: 1.87431*width, y: -0.21506*height), control1: CGPoint(x: 1.87989*width, y: -0.3655*height), control2: CGPoint(x: 1.87906*width, y: -0.27969*height)) + path.addCurve(to: CGPoint(x: 1.87576*width, y: -0.19493*height), control1: CGPoint(x: 1.87348*width, y: -0.20553*height), control2: CGPoint(x: 1.8739*width, y: -0.19811*height)) + path.addLine(to: CGPoint(x: 1.88547*width, y: -0.17586*height)) + path.addCurve(to: CGPoint(x: 1.88919*width, y: -0.18434*height), control1: CGPoint(x: 1.88733*width, y: -0.17268*height), control2: CGPoint(x: 1.88857*width, y: -0.17374*height)) + path.addCurve(to: CGPoint(x: 1.8958*width, y: -0.35279*height), control1: CGPoint(x: 1.89229*width, y: -0.23519*height), control2: CGPoint(x: 1.89456*width, y: -0.29346*height)) + path.addLine(to: CGPoint(x: 1.90386*width, y: -0.33372*height)) + path.addCurve(to: CGPoint(x: 1.90717*width, y: -0.29664*height), control1: CGPoint(x: 1.90717*width, y: -0.3263*height), control2: CGPoint(x: 1.9082*width, y: -0.31783*height)) + path.addCurve(to: CGPoint(x: 1.89952*width, y: -0.14408*height), control1: CGPoint(x: 1.90448*width, y: -0.23625*height), control2: CGPoint(x: 1.90118*width, y: -0.19387*height)) + path.addCurve(to: CGPoint(x: 1.9266*width, y: 0.01271*height), control1: CGPoint(x: 1.89704*width, y: -0.06145*height), control2: CGPoint(x: 1.90924*width, y: 0.01271*height)) + path.addCurve(to: CGPoint(x: 1.96814*width, y: -0.19917*height), control1: CGPoint(x: 1.94913*width, y: 0.01271*height), control2: CGPoint(x: 1.96359*width, y: -0.11018*height)) + path.addCurve(to: CGPoint(x: 1.96587*width, y: -0.22248*height), control1: CGPoint(x: 1.96876*width, y: -0.21082*height), control2: CGPoint(x: 1.96835*width, y: -0.21824*height)) + path.addLine(to: CGPoint(x: 1.95781*width, y: -0.23519*height)) + path.addCurve(to: CGPoint(x: 1.95305*width, y: -0.22248*height), control1: CGPoint(x: 1.95533*width, y: -0.23943*height), control2: CGPoint(x: 1.95388*width, y: -0.23519*height)) + path.closeSubpath() + return path + } +} + +// Ghost +struct Ghost: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + let width = rect.size.width + let height = rect.size.height + path.move(to: CGPoint(x: 0.47*width, y: 0.0815*height)) + path.addCurve(to: CGPoint(x: 0.3148*width, y: 0.1708*height), control1: CGPoint(x: 0.4054*width, y: 0.0893*height), control2: CGPoint(x: 0.353*width, y: 0.1195*height)) + path.addCurve(to: CGPoint(x: 0.2539*width, y: 0.3318*height), control1: CGPoint(x: 0.2841*width, y: 0.2119*height), control2: CGPoint(x: 0.2634*width, y: 0.2668*height)) + path.addCurve(to: CGPoint(x: 0.2517*width, y: 0.4035*height), control1: CGPoint(x: 0.2515*width, y: 0.3483*height), control2: CGPoint(x: 0.2504*width, y: 0.3846*height)) + path.addCurve(to: CGPoint(x: 0.2525*width, y: 0.4167*height), control1: CGPoint(x: 0.2522*width, y: 0.4106*height), control2: CGPoint(x: 0.2526*width, y: 0.4166*height)) + path.addCurve(to: CGPoint(x: 0.2447*width, y: 0.4189*height), control1: CGPoint(x: 0.2524*width, y: 0.4169*height), control2: CGPoint(x: 0.2489*width, y: 0.4179*height)) + path.addCurve(to: CGPoint(x: 0.1841*width, y: 0.4547*height), control1: CGPoint(x: 0.2245*width, y: 0.4241*height), control2: CGPoint(x: 0.2051*width, y: 0.4355*height)) + path.addCurve(to: CGPoint(x: 0.15*width, y: 0.513*height), control1: CGPoint(x: 0.1646*width, y: 0.4723*height), control2: CGPoint(x: 0.15*width, y: 0.4974*height)) + path.addCurve(to: CGPoint(x: 0.1569*width, y: 0.5309*height), control1: CGPoint(x: 0.15*width, y: 0.5195*height), control2: CGPoint(x: 0.1528*width, y: 0.5268*height)) + path.addCurve(to: CGPoint(x: 0.2085*width, y: 0.5309*height), control1: CGPoint(x: 0.165*width, y: 0.539*height), control2: CGPoint(x: 0.1775*width, y: 0.539*height)) + path.addCurve(to: CGPoint(x: 0.264*width, y: 0.5252*height), control1: CGPoint(x: 0.2538*width, y: 0.5191*height), control2: CGPoint(x: 0.2539*width, y: 0.5191*height)) + path.addCurve(to: CGPoint(x: 0.272*width, y: 0.5335*height), control1: CGPoint(x: 0.2701*width, y: 0.529*height), control2: CGPoint(x: 0.2711*width, y: 0.53*height)) + path.addCurve(to: CGPoint(x: 0.4178*width, y: 0.7853*height), control1: CGPoint(x: 0.3036*width, y: 0.6544*height), control2: CGPoint(x: 0.355*width, y: 0.7433*height)) + path.addCurve(to: CGPoint(x: 0.5902*width, y: 0.7895*height), control1: CGPoint(x: 0.4685*width, y: 0.8193*height), control2: CGPoint(x: 0.5271*width, y: 0.8207*height)) + path.addCurve(to: CGPoint(x: 0.6492*width, y: 0.7534*height), control1: CGPoint(x: 0.6081*width, y: 0.7807*height), control2: CGPoint(x: 0.6235*width, y: 0.7713*height)) + path.addCurve(to: CGPoint(x: 0.7453*width, y: 0.709*height), control1: CGPoint(x: 0.7026*width, y: 0.7165*height), control2: CGPoint(x: 0.7188*width, y: 0.709*height)) + path.addCurve(to: CGPoint(x: 0.8012*width, y: 0.7341*height), control1: CGPoint(x: 0.7664*width, y: 0.709*height), control2: CGPoint(x: 0.7842*width, y: 0.717*height)) + path.addCurve(to: CGPoint(x: 0.816*width, y: 0.744*height), control1: CGPoint(x: 0.81*width, y: 0.7429*height), control2: CGPoint(x: 0.8116*width, y: 0.744*height)) + path.addCurve(to: CGPoint(x: 0.8269*width, y: 0.7335*height), control1: CGPoint(x: 0.8201*width, y: 0.744*height), control2: CGPoint(x: 0.8254*width, y: 0.7389*height)) + path.addCurve(to: CGPoint(x: 0.8265*width, y: 0.707*height), control1: CGPoint(x: 0.8284*width, y: 0.7278*height), control2: CGPoint(x: 0.8283*width, y: 0.7154*height)) + path.addCurve(to: CGPoint(x: 0.7937*width, y: 0.6544*height), control1: CGPoint(x: 0.8223*width, y: 0.687*height), control2: CGPoint(x: 0.8115*width, y: 0.6696*height)) + path.addCurve(to: CGPoint(x: 0.7576*width, y: 0.6304*height), control1: CGPoint(x: 0.7808*width, y: 0.6433*height), control2: CGPoint(x: 0.7711*width, y: 0.6369*height)) + path.addCurve(to: CGPoint(x: 0.6647*width, y: 0.6285*height), control1: CGPoint(x: 0.725*width, y: 0.6149*height), control2: CGPoint(x: 0.6977*width, y: 0.6143*height)) + path.addCurve(to: CGPoint(x: 0.6694*width, y: 0.6162*height), control1: CGPoint(x: 0.6633*width, y: 0.6291*height), control2: CGPoint(x: 0.6646*width, y: 0.6257*height)) + path.addCurve(to: CGPoint(x: 0.7549*width, y: 0.3918*height), control1: CGPoint(x: 0.7139*width, y: 0.5273*height), control2: CGPoint(x: 0.7443*width, y: 0.4478*height)) + path.addCurve(to: CGPoint(x: 0.759*width, y: 0.31*height), control1: CGPoint(x: 0.76*width, y: 0.3651*height), control2: CGPoint(x: 0.7616*width, y: 0.3337*height)) + path.addCurve(to: CGPoint(x: 0.6846*width, y: 0.1554*height), control1: CGPoint(x: 0.7528*width, y: 0.252*height), control2: CGPoint(x: 0.7264*width, y: 0.1972*height)) + path.addCurve(to: CGPoint(x: 0.5329*width, y: 0.0815*height), control1: CGPoint(x: 0.6431*width, y: 0.114*height), control2: CGPoint(x: 0.5913*width, y: 0.0888*height)) + path.addCurve(to: CGPoint(x: 0.47*width, y: 0.0815*height), control1: CGPoint(x: 0.518*width, y: 0.0797*height), control2: CGPoint(x: 0.4851*width, y: 0.0797*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 0.534*width, y: 0.0985*height)) + path.addCurve(to: CGPoint(x: 0.6525*width, y: 0.1488*height), control1: CGPoint(x: 0.577*width, y: 0.1042*height), control2: CGPoint(x: 0.6175*width, y: 0.1214*height)) + path.addCurve(to: CGPoint(x: 0.6948*width, y: 0.1922*height), control1: CGPoint(x: 0.663*width, y: 0.157*height), control2: CGPoint(x: 0.6865*width, y: 0.1812*height)) + path.addCurve(to: CGPoint(x: 0.741*width, y: 0.374*height), control1: CGPoint(x: 0.7344*width, y: 0.245*height), control2: CGPoint(x: 0.7506*width, y: 0.3087*height)) + path.addCurve(to: CGPoint(x: 0.6504*width, y: 0.6166*height), control1: CGPoint(x: 0.732*width, y: 0.435*height), control2: CGPoint(x: 0.7061*width, y: 0.5045*height)) + path.addCurve(to: CGPoint(x: 0.6311*width, y: 0.6609*height), control1: CGPoint(x: 0.6311*width, y: 0.6556*height), control2: CGPoint(x: 0.6301*width, y: 0.6579*height)) + path.addCurve(to: CGPoint(x: 0.6403*width, y: 0.6664*height), control1: CGPoint(x: 0.6324*width, y: 0.6646*height), control2: CGPoint(x: 0.6371*width, y: 0.6674*height)) + path.addCurve(to: CGPoint(x: 0.6505*width, y: 0.6588*height), control1: CGPoint(x: 0.6415*width, y: 0.666*height), control2: CGPoint(x: 0.6461*width, y: 0.6626*height)) + path.addCurve(to: CGPoint(x: 0.704*width, y: 0.6353*height), control1: CGPoint(x: 0.6679*width, y: 0.6436*height), control2: CGPoint(x: 0.685*width, y: 0.6362*height)) + path.addCurve(to: CGPoint(x: 0.7833*width, y: 0.6673*height), control1: CGPoint(x: 0.7305*width, y: 0.634*height), control2: CGPoint(x: 0.757*width, y: 0.6447*height)) + path.addCurve(to: CGPoint(x: 0.8108*width, y: 0.7143*height), control1: CGPoint(x: 0.7983*width, y: 0.6803*height), control2: CGPoint(x: 0.8081*width, y: 0.6969*height)) + path.addCurve(to: CGPoint(x: 0.8101*width, y: 0.719*height), control1: CGPoint(x: 0.8116*width, y: 0.7193*height), control2: CGPoint(x: 0.8115*width, y: 0.7198*height)) + path.addCurve(to: CGPoint(x: 0.8065*width, y: 0.716*height), control1: CGPoint(x: 0.8092*width, y: 0.7186*height), control2: CGPoint(x: 0.8076*width, y: 0.7172*height)) + path.addCurve(to: CGPoint(x: 0.7675*width, y: 0.6948*height), control1: CGPoint(x: 0.8*width, y: 0.7088*height), control2: CGPoint(x: 0.7812*width, y: 0.6986*height)) + path.addCurve(to: CGPoint(x: 0.7209*width, y: 0.6953*height), control1: CGPoint(x: 0.7554*width, y: 0.6916*height), control2: CGPoint(x: 0.7341*width, y: 0.6918*height)) + path.addCurve(to: CGPoint(x: 0.6629*width, y: 0.724*height), control1: CGPoint(x: 0.7013*width, y: 0.7005*height), control2: CGPoint(x: 0.6868*width, y: 0.7076*height)) + path.addCurve(to: CGPoint(x: 0.5548*width, y: 0.7864*height), control1: CGPoint(x: 0.5998*width, y: 0.7672*height), control2: CGPoint(x: 0.583*width, y: 0.7769*height)) + path.addCurve(to: CGPoint(x: 0.508*width, y: 0.7947*height), control1: CGPoint(x: 0.5376*width, y: 0.7921*height), control2: CGPoint(x: 0.5265*width, y: 0.7941*height)) + path.addCurve(to: CGPoint(x: 0.4626*width, y: 0.7888*height), control1: CGPoint(x: 0.489*width, y: 0.7953*height), control2: CGPoint(x: 0.4788*width, y: 0.794*height)) + path.addCurve(to: CGPoint(x: 0.3776*width, y: 0.725*height), control1: CGPoint(x: 0.4334*width, y: 0.7796*height), control2: CGPoint(x: 0.4033*width, y: 0.757*height)) + path.addCurve(to: CGPoint(x: 0.3451*width, y: 0.6763*height), control1: CGPoint(x: 0.3696*width, y: 0.715*height), control2: CGPoint(x: 0.3525*width, y: 0.6894*height)) + path.addCurve(to: CGPoint(x: 0.2886*width, y: 0.5293*height), control1: CGPoint(x: 0.3234*width, y: 0.638*height), control2: CGPoint(x: 0.3017*width, y: 0.5813*height)) + path.addCurve(to: CGPoint(x: 0.2683*width, y: 0.3864*height), control1: CGPoint(x: 0.2758*width, y: 0.4785*height), control2: CGPoint(x: 0.2692*width, y: 0.4321*height)) + path.addCurve(to: CGPoint(x: 0.2726*width, y: 0.3205*height), control1: CGPoint(x: 0.2677*width, y: 0.3559*height), control2: CGPoint(x: 0.2684*width, y: 0.3444*height)) + path.addCurve(to: CGPoint(x: 0.4818*width, y: 0.097*height), control1: CGPoint(x: 0.2961*width, y: 0.1862*height), control2: CGPoint(x: 0.3708*width, y: 0.1063*height)) + path.addCurve(to: CGPoint(x: 0.534*width, y: 0.0985*height), control1: CGPoint(x: 0.4951*width, y: 0.0959*height), control2: CGPoint(x: 0.5201*width, y: 0.0966*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 0.2544*width, y: 0.4372*height)) + path.addCurve(to: CGPoint(x: 0.2575*width, y: 0.4589*height), control1: CGPoint(x: 0.2547*width, y: 0.439*height), control2: CGPoint(x: 0.2561*width, y: 0.4488*height)) + path.addCurve(to: CGPoint(x: 0.2656*width, y: 0.5051*height), control1: CGPoint(x: 0.2597*width, y: 0.4749*height), control2: CGPoint(x: 0.2642*width, y: 0.5003*height)) + path.addCurve(to: CGPoint(x: 0.2618*width, y: 0.5053*height), control1: CGPoint(x: 0.266*width, y: 0.5067*height), control2: CGPoint(x: 0.2657*width, y: 0.5067*height)) + path.addCurve(to: CGPoint(x: 0.2233*width, y: 0.5101*height), control1: CGPoint(x: 0.2554*width, y: 0.503*height), control2: CGPoint(x: 0.246*width, y: 0.5042*height)) + path.addCurve(to: CGPoint(x: 0.1775*width, y: 0.5205*height), control1: CGPoint(x: 0.1947*width, y: 0.5175*height), control2: CGPoint(x: 0.1846*width, y: 0.5198*height)) + path.addCurve(to: CGPoint(x: 0.169*width, y: 0.519*height), control1: CGPoint(x: 0.1718*width, y: 0.5211*height), control2: CGPoint(x: 0.171*width, y: 0.521*height)) + path.addCurve(to: CGPoint(x: 0.1791*width, y: 0.4849*height), control1: CGPoint(x: 0.1641*width, y: 0.5141*height), control2: CGPoint(x: 0.1686*width, y: 0.499*height)) + path.addCurve(to: CGPoint(x: 0.2285*width, y: 0.4427*height), control1: CGPoint(x: 0.1894*width, y: 0.4709*height), control2: CGPoint(x: 0.2135*width, y: 0.4504*height)) + path.addCurve(to: CGPoint(x: 0.2527*width, y: 0.434*height), control1: CGPoint(x: 0.2342*width, y: 0.4398*height), control2: CGPoint(x: 0.2501*width, y: 0.4341*height)) + path.addCurve(to: CGPoint(x: 0.2544*width, y: 0.4372*height), control1: CGPoint(x: 0.2534*width, y: 0.434*height), control2: CGPoint(x: 0.2541*width, y: 0.4355*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 0.4813*width, y: 0.2149*height)) + path.addCurve(to: CGPoint(x: 0.4432*width, y: 0.2634*height), control1: CGPoint(x: 0.4651*width, y: 0.2208*height), control2: CGPoint(x: 0.4513*width, y: 0.2383*height)) + path.addCurve(to: CGPoint(x: 0.4356*width, y: 0.312*height), control1: CGPoint(x: 0.4376*width, y: 0.2805*height), control2: CGPoint(x: 0.4356*width, y: 0.2933*height)) + path.addCurve(to: CGPoint(x: 0.4404*width, y: 0.3387*height), control1: CGPoint(x: 0.4356*width, y: 0.3288*height), control2: CGPoint(x: 0.4366*width, y: 0.3342*height)) + path.addCurve(to: CGPoint(x: 0.4655*width, y: 0.3364*height), control1: CGPoint(x: 0.4439*width, y: 0.3427*height), control2: CGPoint(x: 0.4488*width, y: 0.3423*height)) + path.addCurve(to: CGPoint(x: 0.492*width, y: 0.3315*height), control1: CGPoint(x: 0.4793*width, y: 0.3316*height), control2: CGPoint(x: 0.4796*width, y: 0.3316*height)) + path.addCurve(to: CGPoint(x: 0.5195*width, y: 0.3324*height), control1: CGPoint(x: 0.4989*width, y: 0.3315*height), control2: CGPoint(x: 0.5113*width, y: 0.3319*height)) + path.addCurve(to: CGPoint(x: 0.5466*width, y: 0.3276*height), control1: CGPoint(x: 0.5369*width, y: 0.3334*height), control2: CGPoint(x: 0.5416*width, y: 0.3326*height)) + path.addCurve(to: CGPoint(x: 0.552*width, y: 0.2905*height), control1: CGPoint(x: 0.5526*width, y: 0.3216*height), control2: CGPoint(x: 0.5542*width, y: 0.3104*height)) + path.addCurve(to: CGPoint(x: 0.516*width, y: 0.22*height), control1: CGPoint(x: 0.5484*width, y: 0.2589*height), control2: CGPoint(x: 0.5346*width, y: 0.2319*height)) + path.addCurve(to: CGPoint(x: 0.4813*width, y: 0.2149*height), control1: CGPoint(x: 0.5055*width, y: 0.2133*height), control2: CGPoint(x: 0.4916*width, y: 0.2112*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 0.3452*width, y: 0.2165*height)) + path.addCurve(to: CGPoint(x: 0.306*width, y: 0.2848*height), control1: CGPoint(x: 0.3275*width, y: 0.2247*height), control2: CGPoint(x: 0.3104*width, y: 0.2544*height)) + path.addCurve(to: CGPoint(x: 0.3052*width, y: 0.3052*height), control1: CGPoint(x: 0.3053*width, y: 0.2892*height), control2: CGPoint(x: 0.305*width, y: 0.2984*height)) + path.addCurve(to: CGPoint(x: 0.3129*width, y: 0.3277*height), control1: CGPoint(x: 0.3056*width, y: 0.3193*height), control2: CGPoint(x: 0.3072*width, y: 0.3239*height)) + path.addCurve(to: CGPoint(x: 0.3367*width, y: 0.3279*height), control1: CGPoint(x: 0.3171*width, y: 0.3306*height), control2: CGPoint(x: 0.3204*width, y: 0.3306*height)) + path.addCurve(to: CGPoint(x: 0.3708*width, y: 0.3305*height), control1: CGPoint(x: 0.3529*width, y: 0.3252*height), control2: CGPoint(x: 0.3592*width, y: 0.3257*height)) + path.addCurve(to: CGPoint(x: 0.3942*width, y: 0.3371*height), control1: CGPoint(x: 0.3862*width, y: 0.3369*height), control2: CGPoint(x: 0.3912*width, y: 0.3383*height)) + path.addCurve(to: CGPoint(x: 0.3985*width, y: 0.3331*height), control1: CGPoint(x: 0.3957*width, y: 0.3366*height), control2: CGPoint(x: 0.3976*width, y: 0.3347*height)) + path.addCurve(to: CGPoint(x: 0.3964*width, y: 0.2647*height), control1: CGPoint(x: 0.4036*width, y: 0.3231*height), control2: CGPoint(x: 0.4026*width, y: 0.2895*height)) + path.addCurve(to: CGPoint(x: 0.3657*width, y: 0.2155*height), control1: CGPoint(x: 0.39*width, y: 0.2389*height), control2: CGPoint(x: 0.3788*width, y: 0.221*height)) + path.addCurve(to: CGPoint(x: 0.3452*width, y: 0.2165*height), control1: CGPoint(x: 0.3601*width, y: 0.2132*height), control2: CGPoint(x: 0.3514*width, y: 0.2136*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 0.4847*width, y: 0.4141*height)) + path.addCurve(to: CGPoint(x: 0.4028*width, y: 0.4568*height), control1: CGPoint(x: 0.4575*width, y: 0.417*height), control2: CGPoint(x: 0.4287*width, y: 0.432*height)) + path.addCurve(to: CGPoint(x: 0.372*width, y: 0.5039*height), control1: CGPoint(x: 0.3864*width, y: 0.4726*height), control2: CGPoint(x: 0.3753*width, y: 0.4895*height)) + path.addCurve(to: CGPoint(x: 0.3808*width, y: 0.5335*height), control1: CGPoint(x: 0.3692*width, y: 0.5161*height), control2: CGPoint(x: 0.3726*width, y: 0.5277*height)) + path.addCurve(to: CGPoint(x: 0.4297*width, y: 0.5298*height), control1: CGPoint(x: 0.389*width, y: 0.5392*height), control2: CGPoint(x: 0.4035*width, y: 0.5381*height)) + path.addCurve(to: CGPoint(x: 0.463*width, y: 0.521*height), control1: CGPoint(x: 0.4497*width, y: 0.5235*height), control2: CGPoint(x: 0.4592*width, y: 0.521*height)) + path.addCurve(to: CGPoint(x: 0.4835*width, y: 0.5305*height), control1: CGPoint(x: 0.4655*width, y: 0.521*height), control2: CGPoint(x: 0.4712*width, y: 0.5237*height)) + path.addLine(to: CGPoint(x: 0.5004*width, y: 0.5399*height)) + path.addLine(to: CGPoint(x: 0.5042*width, y: 0.5332*height)) + path.addCurve(to: CGPoint(x: 0.508*width, y: 0.5258*height), control1: CGPoint(x: 0.5063*width, y: 0.5295*height), control2: CGPoint(x: 0.508*width, y: 0.5262*height)) + path.addCurve(to: CGPoint(x: 0.4681*width, y: 0.5044*height), control1: CGPoint(x: 0.508*width, y: 0.5246*height), control2: CGPoint(x: 0.4716*width, y: 0.505*height)) + path.addCurve(to: CGPoint(x: 0.4329*width, y: 0.5114*height), control1: CGPoint(x: 0.4626*width, y: 0.5033*height), control2: CGPoint(x: 0.4517*width, y: 0.5055*height)) + path.addCurve(to: CGPoint(x: 0.3905*width, y: 0.5196*height), control1: CGPoint(x: 0.4037*width, y: 0.5206*height), control2: CGPoint(x: 0.3946*width, y: 0.5223*height)) + path.addCurve(to: CGPoint(x: 0.388*width, y: 0.5122*height), control1: CGPoint(x: 0.3883*width, y: 0.5182*height), control2: CGPoint(x: 0.388*width, y: 0.5172*height)) + path.addCurve(to: CGPoint(x: 0.4404*width, y: 0.448*height), control1: CGPoint(x: 0.3881*width, y: 0.4946*height), control2: CGPoint(x: 0.4088*width, y: 0.4693*height)) + path.addCurve(to: CGPoint(x: 0.4875*width, y: 0.4309*height), control1: CGPoint(x: 0.4554*width, y: 0.438*height), control2: CGPoint(x: 0.4691*width, y: 0.433*height)) + path.addCurve(to: CGPoint(x: 0.5648*width, y: 0.4481*height), control1: CGPoint(x: 0.5106*width, y: 0.4283*height), control2: CGPoint(x: 0.5396*width, y: 0.4347*height)) + path.addCurve(to: CGPoint(x: 0.5766*width, y: 0.453*height), control1: CGPoint(x: 0.5699*width, y: 0.4508*height), control2: CGPoint(x: 0.5752*width, y: 0.453*height)) + path.addCurve(to: CGPoint(x: 0.584*width, y: 0.445*height), control1: CGPoint(x: 0.5801*width, y: 0.453*height), control2: CGPoint(x: 0.584*width, y: 0.4488*height)) + path.addCurve(to: CGPoint(x: 0.5658*width, y: 0.43*height), control1: CGPoint(x: 0.584*width, y: 0.4402*height), control2: CGPoint(x: 0.5797*width, y: 0.4367*height)) + path.addCurve(to: CGPoint(x: 0.5108*width, y: 0.414*height), control1: CGPoint(x: 0.5463*width, y: 0.4206*height), control2: CGPoint(x: 0.5309*width, y: 0.4161*height)) + path.addCurve(to: CGPoint(x: 0.4847*width, y: 0.4141*height), control1: CGPoint(x: 0.5003*width, y: 0.4129*height), control2: CGPoint(x: 0.4958*width, y: 0.4129*height)) + path.closeSubpath() + path.move(to: CGPoint(x: 0.4665*width, y: 0.893*height)) + path.addCurve(to: CGPoint(x: 0.3071*width, y: 0.9064*height), control1: CGPoint(x: 0.3762*width, y: 0.8947*height), control2: CGPoint(x: 0.3136*width, y: 0.8999*height)) + path.addCurve(to: CGPoint(x: 0.3093*width, y: 0.9095*height), control1: CGPoint(x: 0.3058*width, y: 0.9078*height), control2: CGPoint(x: 0.306*width, y: 0.9081*height)) + path.addCurve(to: CGPoint(x: 0.6915*width, y: 0.9164*height), control1: CGPoint(x: 0.3396*width, y: 0.9221*height), control2: CGPoint(x: 0.5731*width, y: 0.9264*height)) + path.addCurve(to: CGPoint(x: 0.7394*width, y: 0.9075*height), control1: CGPoint(x: 0.7204*width, y: 0.914*height), control2: CGPoint(x: 0.7389*width, y: 0.9105*height)) + path.addCurve(to: CGPoint(x: 0.4665*width, y: 0.893*height), control1: CGPoint(x: 0.7408*width, y: 0.8978*height), control2: CGPoint(x: 0.604*width, y: 0.8905*height)) + path.closeSubpath() + return path + } +} + +// Aurora +struct AuroraView: View { + + private enum AnimationProperties { + static let animationSpeed: Double = 4 + static let timerDuration: TimeInterval = 3 + static let blurRadius: CGFloat = 130 + } + + @State private var timer = Timer.publish(every: AnimationProperties.timerDuration, on: .main, in: .common).autoconnect() + @ObservedObject private var animator = CircleAnimator(colors: AuroraColors.all) + + var body: some View { + ZStack { + ZStack { + ForEach(animator.circles) { circle in + MovingCircle(originOffset: circle.position) + .foregroundColor(circle.color) + } + }.blur(radius: AnimationProperties.blurRadius) + } + .onDisappear { + timer.upstream.connect().cancel() + } + .onAppear { + animateCircles() + timer = Timer.publish(every: AnimationProperties.timerDuration, on: .main, in: .common).autoconnect() + } + .onReceive(timer) { _ in + animateCircles() + } + } + + private func animateCircles() { + withAnimation(.easeInOut(duration: AnimationProperties.animationSpeed)) { + animator.animate() + } + } + +} + +private enum AuroraColors { + static var all: [Color] { + [ + // Color(red: 0/255, green: 0/255, blue: 128/255), // Dark Blue + Color.purple, // Purple + Color.pink, // Pink + Color.orange, // Orange + ] + } +} + +private struct MovingCircle: Shape { + + var originOffset: CGPoint + + var animatableData: CGPoint.AnimatableData { + get { + originOffset.animatableData + } + set { + originOffset.animatableData = newValue + } + } + + func path(in rect: CGRect) -> Path { + var path = Path() + + let adjustedX = rect.width * originOffset.x + let adjustedY = rect.height * originOffset.y + let smallestDimension = min(rect.width, rect.height) + path.addArc(center: CGPoint(x: adjustedX, y: adjustedY), radius: smallestDimension/2, startAngle: .zero, endAngle: .degrees(360), clockwise: true) + return path + } +} + +private class CircleAnimator: ObservableObject { + class Circle: Identifiable { + internal init(position: CGPoint, color: Color) { + self.position = position + self.color = color + } + var position: CGPoint + let id = UUID().uuidString + let color: Color + } + + @Published private(set) var circles: [Circle] = [] + + + init(colors: [Color]) { + circles = colors.map({ color in + Circle(position: CircleAnimator.generateRandomPosition(), color: color) + }) + } + + func animate() { + objectWillChange.send() + for circle in circles { + circle.position = CircleAnimator.generateRandomPosition() + } + } + + static func generateRandomPosition() -> CGPoint { + CGPoint(x: CGFloat.random(in: 0 ... 1), y: CGFloat.random(in: 0 ... 1)) + } +} + +// Ghost View +// ZStack { +// LinearGradient(colors: [.pink, .orange], startPoint: .topLeading, endPoint: .bottomTrailing) +// .edgesIgnoringSafeArea(.all) +// .hueRotation(.degrees(animateGradient ? 45 : 0)) +// .onAppear { +// withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) { +// animateGradient.toggle() +// } +// } +// .mask( +// Ghost() +// .frame(width: 200, height: 200) +// ) +// } + +// Gradient Background +//ZStack { +// LinearGradient(colors: [.pink, .orange], startPoint: .topLeading, endPoint: .bottomTrailing) +// .edgesIgnoringSafeArea(.all) +// .hueRotation(.degrees(animateGradient ? 45 : 0)) +// .onAppear { +// withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) { +// animateGradient.toggle() +// } +// } +// .mask( +// Ghost() +// .frame(width: 200, height: 200) +// ) +//} diff --git a/Pearcleaner/Logic/Styles.swift b/Pearcleaner/Logic/Styles.swift new file mode 100644 index 0000000..34f1393 --- /dev/null +++ b/Pearcleaner/Logic/Styles.swift @@ -0,0 +1,418 @@ +// +// Styles.swift +// Pearcleaner +// +// Created by Alin Lupascu on 10/31/23. +// + +import Foundation +import SwiftUI + +struct SimpleButtonStyle: ButtonStyle { + @State private var hovered = false + let icon: String + let help: String + let color: Color + + func makeBody(configuration: Self.Configuration) -> some View { + HStack { + Image(systemName: icon) + .resizable() + .scaledToFit() + .frame(width: 20) + .foregroundColor(color) + } + .padding(8) + .background { + if hovered { +// Circle() +// .strokeBorder(Color("AccentColor"), lineWidth: 1) + RoundedRectangle(cornerRadius: 8) + .strokeBorder(Color("AccentColor"), lineWidth: 1) + } + + } + .onHover { hovering in + withAnimation() { + hovered = hovering + } + } + .help(help) + } +} + + +struct LabeledDivider: View { + let label: String + @EnvironmentObject var appState: AppState + + var body: some View { + HStack(spacing: 0) { + Rectangle() + .frame(height: 1) + .foregroundColor(Color("AccentColor").opacity(0.2)) + + Text(label) + .textCase(.uppercase) + .font(.title2) + .foregroundColor(Color("AccentColor").opacity(0.6)) + .padding(.horizontal, 10) + .frame(minWidth: 80) + + Rectangle() + .frame(height: 1) + .foregroundColor(Color("AccentColor").opacity(0.2)) + } + .frame(minHeight: 35) + } +} + + +struct AnimatedSearchStyle: TextFieldStyle { + @State private var isHovered = false + @State var icon: Image? + @State var trash: Bool = false + @Binding var text: String + + func _body(configuration: TextField) -> some View { + + HStack(spacing: 5) { + + if isHovered || !text.isEmpty { + HStack(spacing: 5) { + if icon != nil { + icon + .foregroundColor(Color("AccentColor").opacity(0.5)) + Image(systemName: "chevron.right") + .foregroundColor(Color("AccentColor").opacity(0.3)) + .controlSize(.small) + + } + + configuration + .frame(maxWidth: 300) + .font(.title3) + .textFieldStyle(PlainTextFieldStyle()) + if trash { + Image(systemName: "xmark") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 10, height: 10) + .padding(.trailing, 5) + .foregroundStyle(text.isEmpty ? Color.clear : (isHovered ? Color("AccentColor").opacity(0.8) : Color("AccentColor").opacity(0.5))) + .onTapGesture { + text = "" + } + } + } + } else { + Image(systemName: "magnifyingglass") + .foregroundColor(Color("AccentColor").opacity(0.5)) + .padding(.trailing, 150) + + } + } + .padding(6) + .overlay( + Group { + if isHovered || !text.isEmpty { + RoundedRectangle(cornerRadius: 6) + .strokeBorder(Color("AccentColor").opacity(0.4), lineWidth: 1) + .allowsHitTesting(false) + } + } + ) + .onHover { hovering in + withAnimation(Animation.easeIn(duration: 0.15)) { + self.isHovered = hovering + } + } + } +} + + +struct SimpleSearchStyle: TextFieldStyle { + @State private var isHovered = false + @State var icon: Image? + @State var trash: Bool = false + @Binding var text: String + + func _body(configuration: TextField) -> some View { + + HStack(spacing: 5) { + + HStack(spacing: 5) { + if icon != nil { + icon + .foregroundColor(Color("mode").opacity(0.5)) + } + + configuration + .frame(maxWidth: 300) + .font(.title3) + .textFieldStyle(PlainTextFieldStyle()) + if trash { + Image(systemName: "xmark") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 10, height: 10) + .padding(.trailing, 5) + .foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5)) + .onTapGesture { + text = "" + } + .opacity(text.isEmpty ? 0 : 1) + } + } + + } + .padding(6) + .overlay( + Group { + RoundedRectangle(cornerRadius: 6) + .strokeBorder(Color("mode").opacity(0.2), lineWidth: 1) + .allowsHitTesting(false) + + } + ) + .onHover { hovering in + withAnimation(Animation.easeIn(duration: 0.15)) { + self.isHovered = hovering + } + } + } +} + + +struct GlassEffect: NSViewRepresentable { + var material: NSVisualEffectView.Material // Choose the material you want + var blendingMode: NSVisualEffectView.BlendingMode // Choose the blending mode + + func makeNSView(context: Self.Context) -> NSView { + let visualEffectView = NSVisualEffectView() + visualEffectView.material = material + visualEffectView.blendingMode = blendingMode + return visualEffectView + } + + func updateNSView(_ nsView: NSView, context: Context) { } +} + + + +struct VerticalDivider: View { + + var color: Color = Color("AccentColor") + var width: CGFloat = 1 + var height: CGFloat = 20 + var opacity: Double = 1 + + var body: some View { + Divider() + .foregroundColor(color) + .frame(width: width, height: height) + .opacity(opacity) + .ignoresSafeArea(.all) + } +} + + + + +struct WindowActionButton: ButtonStyle { + enum UserAction { + case accept + case cancel + } + @State private var hovered = false + let action: UserAction + + func makeBody(configuration: Configuration) -> some View { + configuration.label + .frame(width: 100) + .padding(10) + .background( + !configuration.isPressed ? + !hovered ? + action == .accept ? Color("AccentColor") : Color.red : + action == .accept ? Color("AccentColor").opacity(0.8) : Color.red.opacity(0.8) : + action == .accept ? Color("AccentColor").opacity(0.5) : Color.red.opacity(0.5) + ) + .foregroundColor(.white) + .cornerRadius(8) + .onHover { hovering in + withAnimation(Animation.easeIn(duration: 0.15)) { + hovered = hovering + } + } + } +} + + + + + + + +// Picker +//struct PillPicker: View { +// @Binding var index: Int +// var onTapAction: () -> Void +// +// var body: some View { +// +// HStack(alignment: .center, spacing: 20) { +// ForEach(0..<3) { i in +// HStack(spacing: 4) { +// Image(systemName: i == 0 ? "appclip" : "ellipsis.circle") +// .resizable() +// .scaledToFit() +// .frame(width: 16) +// .foregroundColor(index == i ? .black : .gray) +// +// Text(i == 0 ? "Apps" : (i == 1 ? "Widgets" : "Plugins")) +// .font(.system(size: 12)) +// .foregroundColor(index == i ? .black : .gray) +// } +// .padding(8) +// .background((Color.white).opacity(index == i ? 1 : 0)) +// .clipShape(Capsule()) +// .onTapGesture { +// withAnimation { +// index = i +// onTapAction() +// } +// } +// } +// } +// .background(Color.black.opacity(0.06)) +// .clipShape(Capsule()) +// } +//} + +struct PillPicker: View { + @Binding var index: Int + var onTapAction: () -> Void + @Environment(\.colorScheme) var colorScheme + + var body: some View { + HStack(alignment: .center, spacing: 10) { + ForEach(0..<3) { i in + ZStack { + Capsule() + .fill(Color.white) + .offset(x: (CGFloat(index - i) * 100)) + .animation(.default, value: index) + .opacity(index == i ? 1 : 0) + .scaleEffect(index == i ? 1 : 0.70) + .shadow(color: Color.black.opacity(0.2), radius: 2, x: 0, y: 2) + + HStack(spacing: 0) { + // Uncomment below for icon next to labels +// Image(systemName: i == 0 ? "appclip" : (i == 1 ? "macwindow" : "cube.box.fill")) +// .resizable() +// .scaledToFit() +// .frame(width: 16) +// .foregroundColor(index == i ? .black : .gray) + + Text(i == 0 ? "Apps" : (i == 1 ? "Widgets" : "Plugins")) + .font(.system(size: 12)) + .foregroundColor(index == i ? (colorScheme == .dark ? .black : Color("AccentColor")) : .gray) + } + .padding(5) + .frame(height: 25) + .background(.white.opacity(0.0001)) + } + .onTapGesture { + withAnimation { + index = i + onTapAction() + } + } + } + } + .frame(height: 25) + .padding(5) + .background( + Capsule() + .fill(colorScheme == .dark ? .white.opacity(0.1) : .black.opacity(0.06)) + .overlay( + Capsule() + .stroke(Color.black.opacity(colorScheme == .dark ? 0.8 : 0.2), lineWidth: 1) + .blur(radius: 1) + .offset(y: 1) + ) + ) +// .background(Color.black.opacity(0.06)) + .clipShape(Capsule()) + } +} + + + + + + + + + + +// .frame(height: 50) + +// HStack(spacing: 10) { +// HStack(spacing: 2) { +// Image(systemName: "appclip") +// .foregroundColor(index == 0 ? .black : .gray) +// Text("Apps") +// .font(.footnote) +// .foregroundColor(index == 0 ? .black : .gray) +// } +// .padding(8) +// .background((Color.white).opacity(index == 0 ? 1 : 0)) +// .clipShape(Capsule()) +// .onTapGesture { +// withAnimation { +// index = 0 +// onTapAction() +// } +// } +// +// HStack(spacing: 2) { +// Image(systemName: "ellipsis.circle") +// .foregroundColor(index == 1 ? .black : .gray) +// Text("Widgets") +// .foregroundColor(index == 1 ? .black : .gray) +// +// +// } +// .padding(8) +// .background((Color.white).opacity(index == 1 ? 1 : 0)) +// .clipShape(Capsule()) +// .onTapGesture { +// withAnimation { +// index = 1 +// onTapAction() +// } +// } +// +// HStack(spacing: 2) { +// Image(systemName: "ellipsis.circle") +// .foregroundColor(index == 2 ? .black : .gray) +// Text("Plugins") +// .foregroundColor(index == 2 ? .black : .gray) +// +// +// } +// .padding(8) +// .background((Color.white).opacity(index == 2 ? 2 : 0)) +// .clipShape(Capsule()) +// .onTapGesture { +// withAnimation { +// index = 2 +// onTapAction() +// } +// } +// } +// .background(Color.black.opacity(0.06)) +// .clipShape(Capsule()) +// .frame(height: 50) diff --git a/Pearcleaner/Logic/Utilities.swift b/Pearcleaner/Logic/Utilities.swift new file mode 100644 index 0000000..dad15f0 --- /dev/null +++ b/Pearcleaner/Logic/Utilities.swift @@ -0,0 +1,509 @@ +// +// Utilities.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/3/23. +// + +import Foundation +import SwiftUI + +// Make updates on main thread +func updateOnMain(_ updates: @escaping () -> Void) { + DispatchQueue.main.async { + updates() + } +} + + +// Execute functions on background thread +func updateOnBackground(_ updates: @escaping () -> Void) { + DispatchQueue.global(qos: .background).async { + updates() + } +} + + +// Check for access to Full Disk access +func checkAndRequestFullDiskAccess(appState: AppState, skipAlert: Bool = false) -> Bool { + @AppStorage("settings.permissions.disk") var diskP: Bool = false + + let fileURL = URL(fileURLWithPath: "\(home)/Library/Application Support/com.apple.TCC/TCC.db") + + let accessStatus = FileManager.default.isWritableFile(atPath: fileURL.path) + if accessStatus { + diskP = true + _ = checkAndRequestAccessibilityAccess(appState: appState) + + return true + } else { + diskP = false + if !skipAlert { + appState.alertType = .diskAccess + appState.showAlert = true + } + + return false + } +} + + +// Check for access to System Events +func checkAndRequestAccessibilityAccess(appState: AppState) -> Bool { + @AppStorage("settings.permissions.events") var diskE: Bool = false + + let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true] + let accessEnabled = AXIsProcessTrustedWithOptions(options) + if accessEnabled { + diskE = true + return accessEnabled + } else { + diskE = false + return false + + } +} + + + + +// Check if symlink +func isSymlink(atPath path: URL) -> Bool { + do { + let _ = try path.checkResourceIsReachable() + let resourceValues = try path.resourceValues(forKeys: [.isSymbolicLinkKey]) + return resourceValues.isSymbolicLink == true + } catch { + return false + } +} + + +// Open trash folder +func openTrash() { + if let trashURL = try? FileManager.default.url(for: .trashDirectory, in: .userDomainMask, appropriateFor: nil, create: false) { + NSWorkspace.shared.open(trashURL) + } +} + +// Check if restricted app +func isRestricted(atPath path: URL) -> Bool { + if path.path.contains("Safari") || path.path.contains(Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "") { + return true + } else { + return false + } +} + + +// Convert icon to png so colors render correctly +func convertICNSToPNG(icon: NSImage, size: NSSize) -> NSImage? { + // Resize the icon to the specified size + let resizedIcon = NSImage(size: size) + resizedIcon.lockFocus() + icon.draw(in: NSRect(x: 0, y: 0, width: size.width, height: size.height)) + resizedIcon.unlockFocus() + + // Convert the resized icon to PNG format + if let resizedImageData = resizedIcon.tiffRepresentation, + let resizedBitmap = NSBitmapImageRep(data: resizedImageData), + let pngData = resizedBitmap.representation(using: .png, properties: [:]) { + return NSImage(data: pngData) + } + + return nil +} + +// Get icon for files and folders +func getIconForFileOrFolder(atPath path: URL) -> Image? { + let icon = NSWorkspace.shared.icon(forFile: path.path) + let nsImage = icon + return Image(nsImage: nsImage) +} + + +// Relaunch app +func relaunchApp(afterDelay seconds: TimeInterval = 0.5) -> Never { + let task = Process() + task.launchPath = "/bin/sh" + task.arguments = ["-c", "sleep \(seconds); open \"\(Bundle.main.bundlePath)\""] + task.launch() + + NSApp.terminate(nil) + exit(0) +} + + +// --- Extend Int to convert hours to seconds --- +extension Int { + var daysToSeconds: Double { + return Double(self) * 24 * 60 * 60 + } +} + + +// --- Extend String to remove periods, spaces and lowercase the string +extension String { + func pearFormat() -> String { + return self.replacingOccurrences(of: ".", with: "").replacingOccurrences(of: " ", with: "").lowercased() + } +} + + +// --- Trash Relationship --- +extension FileManager { + public func isInTrash(_ file: URL) -> Bool { + var relationship: URLRelationship = .other + try? getRelationship(&relationship, of: .trashDirectory, in: .userDomainMask, toItemAt: file) + return relationship == .contains + } +} + + +// --- Gradient --- +func schemeGradient(for colorScheme: ColorScheme) -> LinearGradient { + return LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing) +// switch colorScheme { +// case .light: +// return LinearGradient(gradient: Gradient(colors: [Color("AccentColor")]), startPoint: .leading, endPoint: .trailing) +// case .dark: +// return LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing) +// @unknown default: +// return LinearGradient(gradient: Gradient(colors: [Color("AccentColor")]), startPoint: .leading, endPoint: .trailing) +// } +} + + + +// Get total size of folders and files using DU cli command +func totalSizeOnDisk(for paths: [URL]) -> String? { + var totalSize = 0 + + let process = Process() + process.launchPath = "/usr/bin/du" + process.arguments = ["-sk"] + paths.map { (url: URL) -> String in + return url.path + } + let pipe = Pipe() + process.standardOutput = pipe + + try? process.run() + process.waitUntilExit() + + let data = pipe.fileHandleForReading.readDataToEndOfFile() + if let output = String(data: data, encoding: .utf8) { + let lines = output.components(separatedBy: .newlines) + for line in lines { + let components = line.components(separatedBy: "\t") + if let sizeString = components.first, let size = Int(sizeString) { + totalSize += size * 1024 // Convert the size from kilobytes to bytes + } + } + } + + let byteCountFormatter = ByteCountFormatter() + byteCountFormatter.countStyle = .file + byteCountFormatter.allowedUnits = [.useAll] + return byteCountFormatter.string(fromByteCount: Int64(totalSize)) +} + +func totalSizeOnDisk(for path: URL) -> String? { + return totalSizeOnDisk(for: [path]) +} + + +// Get total size of folders and files using straight swift +extension URL { + func totalAllocatedSize(includingSubfolders: Bool = false) throws -> Int? { + return try [self].totalAllocatedSize(includingSubfolders: includingSubfolders) + } + + func totalSizeOnDisk(includingSubfolders: Bool = false) throws -> String? { + return try [self].totalSizeOnDisk(includingSubfolders: includingSubfolders) + } +} + +extension Array where Element == URL { + func totalAllocatedSize(includingSubfolders: Bool = false) throws -> Int? { + var totalSize = 0 + + for path in self { +// if path.absoluteString.contains(".app") { + let resourceValues = try path.resourceValues(forKeys: [.isDirectoryKey, .isPackageKey, .totalFileAllocatedSizeKey]) + + if resourceValues.isDirectory == true || path.pathExtension == "app" { + if includingSubfolders { + let filePaths = FileManager.default.subpaths(atPath: path.path) ?? [] + for filePath in filePaths { + let fileUrl = path.appendingPathComponent(filePath) + let fileAttributes = try FileManager.default.attributesOfItem(atPath: fileUrl.path) + let fileSize = fileAttributes[.size] as? Int64 ?? 0 + totalSize += Int(fileSize) + } + } + } else { + totalSize += resourceValues.totalFileAllocatedSize ?? 0 + } +// } + + } + + return totalSize + } + + func totalSizeOnDisk(includingSubfolders: Bool = false) throws -> String? { + if let totalSize = try self.totalAllocatedSize(includingSubfolders: includingSubfolders) { + let byteCountFormatter = ByteCountFormatter() + byteCountFormatter.countStyle = .file + byteCountFormatter.allowedUnits = [.useBytes, .useKB, .useMB, .useTB] + return byteCountFormatter.string(fromByteCount: Int64(totalSize)) + } + return nil + } +} + + +// Alerts +func presentAlert(appState: AppState) -> Alert { + + switch appState.alertType { + case .update: + return Alert(title: Text("Update Available 🥳"), message: Text("You may choose to install the update now, otherwise you may start the update later from Settings"), primaryButton: .default(Text("Install")) { + downloadUpdate(appState: appState) + appState.alertType = .off + }, secondaryButton: .cancel()) + case .no_update: + return Alert(title: Text("No Updates 😌"), message: Text("The application is on the latest release available"), primaryButton: .cancel(Text("Okay")), secondaryButton: .default(Text("Force Update")) { + downloadUpdate(appState: appState) + appState.alertType = .off + }) + case .diskAccess: + return Alert(title: Text("Permissions"), message: Text("This application requires Full Disk and Accessibility permissions. Once you grant full disk, don't restart the app yet. Wait a second for a second prompt for accessibility and then restart"), primaryButton: .default(Text("Allow in Settings")) { + if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") { + NSWorkspace.shared.open(url) + } + appState.alertType = .off + }, secondaryButton: .cancel(Text("Later"))) +// case .eventsAccess: +// return Alert(title: Text("Accessibility Permission"), message: Text("This application requires Accessibility permission"), primaryButton: .default(Text("Allow in Settings")) { +// if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") { +// NSWorkspace.shared.open(url) +// } +// appState.alertType = .off +// }, secondaryButton: .cancel(Text("Later"))) + case .restartApp: + return Alert(title: Text("Update Completed!"), message: Text("The application has been updated to the latest version, would you like to restart now?"), primaryButton: .default(Text("Restart")), secondaryButton: .cancel(Text("Later")) { + appState.alertType = .off + relaunchApp(afterDelay: 1) + }) + case .off: + return Alert(title: Text("")) + } +} + + + +// --- Create Application Support folder if it doesn't exist --- +func ensureApplicationSupportFolderExists(appState: AppState) { + let fileManager = FileManager.default + let supportURL = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!.appendingPathComponent("Pearcleaner") + + // Check to make sure Application Support/Support Admin folder exists + if !fileManager.fileExists(atPath: supportURL.path) { + try! fileManager.createDirectory(at: supportURL, withIntermediateDirectories: true) + print("Created Application Support/Pearcleaner folder") + } +} + + + +func launchctl(load: Bool) { + let cmd = load ? "load" : "unload" + if let plistPath = Bundle.main.path(forResource: "com.alienator88.PearcleanerSentinel", ofType: "plist") { + var plistContent = try! String(contentsOfFile: plistPath) + let executableURL = Bundle.main.bundleURL.appendingPathComponent("Contents/MacOS/PearcleanerSentinel") + + // Replace the placeholder with the actual executable path + plistContent = plistContent.replacingOccurrences(of: "__EXECUTABLE_PATH__", with: executableURL.path) + + // Create a temporary plist file with the updated content + let temporaryPlistURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("com.alienator88.PearcleanerSentinel.plist") + + do { + try plistContent.write(to: temporaryPlistURL, atomically: false, encoding: .utf8) + } catch { + print("Error writing the temporary plist file: \(error)") + return + } + let task = Process() + task.launchPath = "/bin/launchctl" + task.arguments = [cmd, "-w", temporaryPlistURL.path] + + let pipe = Pipe() + task.standardOutput = pipe + task.standardError = pipe + + task.launch() + +// let data = pipe.fileHandleForReading.readDataToEndOfFile() +// if let output = String(data: data, encoding: .utf8) { +// print("Output: \(output)") +// } + } +} + +//func unloadAgent() { +// if let plistPath = Bundle.main.path(forResource: "com.alienator88.PearcleanerMonitor", ofType: "plist") { +// var plistContent = try! String(contentsOfFile: plistPath) +// let executableURL = Bundle.main.bundleURL.appendingPathComponent("Contents/MacOS/PearcleanerMonitor") +// +// // Replace the placeholder with the actual executable path +// plistContent = plistContent.replacingOccurrences(of: "__EXECUTABLE_PATH__", with: executableURL.path) +// +// // Create a temporary plist file with the updated content +// let temporaryPlistURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("com.alienator88.PearcleanerMonitor.plist") +// +// do { +// try plistContent.write(to: temporaryPlistURL, atomically: false, encoding: .utf8) +// } catch { +// print("Error writing the temporary plist file: \(error)") +// return +// } +// let task = Process() +// task.launchPath = "/bin/launchctl" +// task.arguments = ["unload", "-w", temporaryPlistURL.path] +// +// let pipe = Pipe() +// task.standardOutput = pipe +// task.standardError = pipe +// +// task.launch() +// +//// let data = pipe.fileHandleForReading.readDataToEndOfFile() +//// if let output = String(data: data, encoding: .utf8) { +//// print("Output: \(output)") +//// } +// } +//} + + + + + + + + + + + + + +//import FileWatcher +// +//// MARK: https://github.com/eonist/FileWatcher +// +//func fileW() { +// let filewatcher = FileWatcher([NSString(string: "~/.Trash").expandingTildeInPath]) +// filewatcher.queue = DispatchQueue.global() +// filewatcher.callback = { event in +// print("Something happened here: " + event.path) +// } +// +// filewatcher.start() +//} + + + +//extension Array where Element == URL { +// // DU shell way of getting sizes +// func totalAllocatedSize2(includingSubfolders: Bool = false) throws -> Int? { +// var totalSize = 0 +// +// for path in self { +// let process = Process() +// process.launchPath = "/usr/bin/du" +// process.arguments = ["-sk", path.path] +// +// let pipe = Pipe() +// process.standardOutput = pipe +// +// try process.run() +// process.waitUntilExit() +// +// let data = pipe.fileHandleForReading.readDataToEndOfFile() +// if let output = String(data: data, encoding: .utf8) { +// let sizeString = output.components(separatedBy: "\t").first ?? "" +// if let size = Int(sizeString) { +// totalSize += size * 1024 +// } +// } +// } +// return totalSize +// } +// +// func totalAllocatedSize(includingSubfolders: Bool = false) throws -> Int? { +// var totalSize = 0 +// +// for path in self { +// if includingSubfolders { +// guard +// let urls = FileManager.default.enumerator(at: path, includingPropertiesForKeys: nil)?.allObjects as? [URL] else { return nil } +// let pathSize = try urls.lazy.reduce(0) { +// (try $1.resourceValues(forKeys: [.totalFileAllocatedSizeKey]).totalFileAllocatedSize ?? 0) + $0 +// } +// totalSize += pathSize +// } else { +// let pathSize = try FileManager.default.contentsOfDirectory(at: path, includingPropertiesForKeys: nil).lazy.reduce(0) { +// (try $1.resourceValues(forKeys: [.totalFileAllocatedSizeKey]) +// .totalFileAllocatedSize ?? 0) + $0 +// } +// totalSize += pathSize +// } +// } +// +// return totalSize +// } +// +// func totalSizeOnDisk(includingSubfolders: Bool = false) throws -> String? { +// if let totalSize = try self.totalAllocatedSize(includingSubfolders: includingSubfolders) { +// let byteCountFormatter = ByteCountFormatter() +// byteCountFormatter.countStyle = .file +// byteCountFormatter.allowedUnits = [.useBytes, .useKB, .useMB, .useTB] +// return byteCountFormatter.string(fromByteCount: Int64(totalSize)) +// } +// return nil +// } +//} + + + + + + + +//func isSymbolicLink(atPath path: URL) -> Bool { +//// let fileManager = FileManager.default +// +// do { +//// let path = "/Applications/Safari.app" +//// let url = URL(fileURLWithPath: path) +// let destinationPath = path.resolvingSymlinksInPath().path +// print("The symlink at \(path) points to \(destinationPath)") +// return true +// } catch { +// print("An error occurred: \(error)") +// return false +// } +// return false +//// var isDirectory = false +//// let exists = FileManager.default.fileExists(atPath: path, isDirectory: isDirectory) +//// if exists && isDirectory { +//// do { +//// let _ = try FileManager.default.destinationOfSymbolicLink(atPath: path) +//// return true +//// } catch { +//// return false +//// } +//// } +//// return false +//} diff --git a/Pearcleaner/PearcleanerApp.swift b/Pearcleaner/PearcleanerApp.swift new file mode 100644 index 0000000..ae686f0 --- /dev/null +++ b/Pearcleaner/PearcleanerApp.swift @@ -0,0 +1,92 @@ +// +// PearcleanerApp.swift +// Pearcleaner +// +// Created by Alin Lupascu on 10/31/23. +// + +import SwiftUI +import AppKit + +@main +struct PearcleanerApp: App { + @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + @StateObject var appState = AppState() + @AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1 + @AppStorage("settings.permissions.disk") private var diskP: Bool = false + @AppStorage("settings.permissions.events") private var diskE: Bool = false + @AppStorage("displayMode") var displayMode: DisplayMode = .dark + @State private var search = "" + + var body: some Scene { + + WindowGroup { + AppListView(search: $search) + .environmentObject(appState) + .frame(minWidth: 1020, minHeight: 700) + .preferredColorScheme(displayMode.colorScheme) + .alert(isPresented: $appState.showAlert) { presentAlert(appState: appState) } + .handlesExternalEvents(preferring: Set(arrayLiteral: "pear"), allowing: Set(arrayLiteral: "*")) + .onAppear { + NSWindow.allowsAutomaticWindowTabbing = false + + // Get Apps + let sortedApps = getSortedApps() + appState.sortedApps.userApps = sortedApps.userApps + appState.sortedApps.systemApps = sortedApps.systemApps + + Task { + +#if !DEBUG + + // Make sure App Support folder exists in the future if needed for storage +// ensureApplicationSupportFolderExists(appState: appState) + + // Check for updates + if diskP && diskE { + loadGithubReleases(appState: appState) + } + + // Check for disk/accessibility permissions + _ = checkAndRequestFullDiskAccess(appState: appState) + + + // TIMERS //////////////////////////////////////////////////////////////////////////////////// + + // Check for app updates every 8 hours or whatever user saved setting. Also refresh autosuggestion list + let updateSeconds = updateTimeframe.daysToSeconds + _ = Timer.scheduledTimer(withTimeInterval: updateSeconds, repeats: true) { _ in + DispatchQueue.main.async { + loadGithubReleases(appState: appState) + } + } + +#endif + } + } + } + .windowStyle(.hiddenTitleBar) + .windowToolbarStyle(.unified) + .windowResizability(.contentMinSize) + .commands { + AppCommands(appState: appState) + CommandGroup(replacing: .newItem, addition: { }) + } + + Settings { + SettingsView() + .environmentObject(appState) + .toolbarBackground(.clear) + .preferredColorScheme(displayMode.colorScheme) + } + } +} + + + + +class AppDelegate: NSObject, NSApplicationDelegate { + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/Pearcleaner/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/Pearcleaner/Resources/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..4f9ac77 --- /dev/null +++ b/Pearcleaner/Resources/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0x59", + "green" : "0x48", + "red" : "0xFF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0x59", + "green" : "0x48", + "red" : "0xFF" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..64dc11e --- /dev/null +++ b/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "filename" : "icon_16x16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "icon_16x16@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "icon_32x32.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "icon_32x32@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "icon_128x128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "icon_128x128@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "icon_256x256.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "icon_256x256@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "icon_512x512.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "icon_512x512@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..3100fc42df8783904a587b659445c8d0dcdd2563 GIT binary patch literal 7360 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 L(o(FEw+Q(k19SQf literal 0 HcmV?d00001 diff --git a/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1792688f31b1ed45058d3df12f038571e557977d GIT binary patch literal 16749 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 Jl_Ev~{{ys$8h-!) literal 0 HcmV?d00001 diff --git a/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..0808d053b0928630eaff0f93ce7fede2dcff2df5 GIT binary patch literal 662 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 Jl_Ev~{{ys$8h-!) literal 0 HcmV?d00001 diff --git a/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..15cec3a9f64abb8ab5548cc05a39735dccd75c79 GIT binary patch literal 39998 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 HemDLHdQc$h literal 0 HcmV?d00001 diff --git a/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..c1ba5830a530032cf5c5de8fe85d5b31f618cd07 GIT binary patch literal 1437 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 HemDLHdQc$h literal 0 HcmV?d00001 diff --git a/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/Pearcleaner/Resources/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..98ca819ff13460be2ff44c2219c1d5c1507787c8 GIT binary patch literal 96757 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]YA^8GuGR~XVYCPVwIVi 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 XS!uHyw{DHJ0LP{cn|~@<7yHM*2EKl) literal 0 HcmV?d00001 diff --git a/Pearcleaner/Resources/Assets.xcassets/Contents.json b/Pearcleaner/Resources/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Pearcleaner/Resources/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Pearcleaner/Resources/Assets.xcassets/logo.imageset/Contents.json b/Pearcleaner/Resources/Assets.xcassets/logo.imageset/Contents.json new file mode 100644 index 0000000..38a858c --- /dev/null +++ b/Pearcleaner/Resources/Assets.xcassets/logo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "logo_combo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Pearcleaner/Resources/Assets.xcassets/logo.imageset/logo_combo.png b/Pearcleaner/Resources/Assets.xcassets/logo.imageset/logo_combo.png new file mode 100644 index 0000000000000000000000000000000000000000..ae575d542a128d29efca616c252631e016fea6df GIT binary patch literal 20291 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 z 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 + + + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + com.alienator88.Pearcleaner + CFBundleURLSchemes + + pear + + + + + diff --git a/Pearcleaner/Resources/Pearcleaner.entitlements b/Pearcleaner/Resources/Pearcleaner.entitlements new file mode 100644 index 0000000..757dd9c --- /dev/null +++ b/Pearcleaner/Resources/Pearcleaner.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.automation.apple-events + + com.apple.security.files.user-selected.read-only + + + diff --git a/Pearcleaner/Resources/com.alienator88.PearcleanerSentinel.plist b/Pearcleaner/Resources/com.alienator88.PearcleanerSentinel.plist new file mode 100644 index 0000000..fde0cbe --- /dev/null +++ b/Pearcleaner/Resources/com.alienator88.PearcleanerSentinel.plist @@ -0,0 +1,16 @@ + + + + + Label + com.alienator88.PearcleanerSentinel + ProgramArguments + + __EXECUTABLE_PATH__ + + RunAtLoad + + KeepAlive + + + diff --git a/Pearcleaner/Settings/About.swift b/Pearcleaner/Settings/About.swift new file mode 100644 index 0000000..6edc9dc --- /dev/null +++ b/Pearcleaner/Settings/About.swift @@ -0,0 +1,172 @@ +// +// About.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/5/23. +// + +import SwiftUI + +struct AboutSettingsTab: View { + @EnvironmentObject var appState: AppState + + var body: some View { + + VStack { + + HStack(alignment: .center) { + VStack(alignment: .center, spacing: 10){ + Spacer() + + Image(nsImage: NSApp.applicationIconImage) + .padding() +// .padding(.bottom, 5) + + HStack(alignment: .center, spacing: 20) { + Button("") { + loadGithubReleases(appState: appState, manual: true) + } + .buttonStyle(SimpleButtonStyle(icon: "cloud", help: "Update application", color: Color("AccentColor"))) + + Button("") { + NSWorkspace.shared.open(URL(string: "https://github.com/ghosted-labs/Pearcleaner")!) + } + .buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View repository", color: Color("AccentColor"))) + } + + Spacer() + + + } +// .padding() + // .padding(.top, 10) + .frame(width: 250) + + VStack(alignment: .center, spacing: 20) { + HStack(alignment: .firstTextBaseline) { + Text(Bundle.main.name) + .font(.title) + .bold() + Spacer() + HStack { + Text("v\(Bundle.main.version)") + Text(" (build \(Bundle.main.buildVersion))") + } + + } + Divider() + .padding(.top, -8) + + VStack(alignment: .leading) { + + HStack{ + Image(systemName: "applescript.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 16, height: 16) + + VStack(alignment: .leading){ + Text("Privacy Guides") + Text("Inspired by open-source appcleaner script from Sun Knudsen").font(.footnote).foregroundStyle(.gray) + + } + Spacer() + + Button("") { + NSWorkspace.shared.open(URL(string: "https://sunknudsen.com/privacy-guides/how-to-clean-uninstall-macos-apps-using-appcleaner-open-source-alternative")!) + } + .buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View", color: Color("AccentColor"))) + + } + .padding() + .background(Color("mode").opacity(0.05)) + .cornerRadius(8) + + + HStack{ + Image(systemName: "trash.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 16, height: 16) + + VStack(alignment: .leading){ + Text("AppCleaner") + Text("Inspired by AppCleaner from Freemacsoft").font(.footnote).foregroundStyle(.gray) + + } + Spacer() + Button(""){ + NSWorkspace.shared.open(URL(string: "https://freemacsoft.net/appcleaner/")!) + } + .buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View", color: Color("AccentColor"))) + + } + .padding() + .background(Color("mode").opacity(0.05)) + .cornerRadius(8) + + +// HStack{ +// Image(systemName: "paintbrush.fill") +// .resizable() +// .aspectRatio(contentMode: .fit) +// .frame(width: 16, height: 16) +// VStack(alignment: .leading){ +// Text("Icon") +// Text("Created by Oviotti on DeviantArt").font(.footnote).foregroundStyle(.gray) +// } +// Spacer() +// +// Button("") { +// NSWorkspace.shared.open(URL(string: "https://www.deviantart.com/oviotti/art/AppCleaner-for-macOS-632260251")!) +// } +// .buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View", color: Color("AccentColor"))) +// +// } +// .padding() +// .background(Color("mode").opacity(0.05)) +// .cornerRadius(8) + + } + + Spacer() + + } + .padding(.trailing) +// .padding() +// .padding(.top, 30) + } + + Spacer() + + Text("Made with ❤️ by Alin Lupascu").font(.footnote).padding(.bottom) + } + .padding(20) + .frame(width: 750, height: 325) + + } +} + + + +extension Bundle { + + var name: String { + func string(for key: String) -> String? { + object(forInfoDictionaryKey: key) as? String + } + return string(for: "CFBundleDisplayName") + ?? string(for: "CFBundleName") + ?? "N/A" + } + + var version: String { + infoDictionary?["CFBundleShortVersionString"] as? String ?? "N/A" + } + + var buildVersion: String { + infoDictionary?["CFBundleVersion"] as? String ?? "N/A" + } + +} + diff --git a/Pearcleaner/Settings/General.swift b/Pearcleaner/Settings/General.swift new file mode 100644 index 0000000..8fd7896 --- /dev/null +++ b/Pearcleaner/Settings/General.swift @@ -0,0 +1,64 @@ +// +// General.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/5/23. +// + +import Foundation +import SwiftUI + +struct GeneralSettingsTab: View { + @EnvironmentObject var appState: AppState + @AppStorage("settings.general.glass") private var glass: Bool = true +// @AppStorage("settings.general.ants") private var ants: Bool = false + + var body: some View { + Form { + VStack { + HStack { + VStack(alignment: .leading, spacing: 5) { + Text("Transparency").font(.title2) + Text("Toggles the sidebar material on the app list drawer") + .font(.footnote) + .foregroundStyle(.gray) + } + Spacer() + Toggle(isOn: $glass, label: { + }) + .toggleStyle(.switch) + } + .padding() + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color("mode").opacity(0.05)) + ) + +// HStack { +// VStack(alignment: .leading, spacing: 5) { +// Text("Animation").font(.title2) +// Text("Toggles the marching ants animation on the drop zone") +// .font(.footnote) +// .foregroundStyle(.gray) +// } +// Spacer() +// Toggle(isOn: $ants, label: { +// }) +// .toggleStyle(.switch) +// } +// .padding() +// .background( +// RoundedRectangle(cornerRadius: 8) +// .fill(Color("mode").opacity(0.05)) +// ) + + Spacer() + } + + } + .padding(20) + .frame(width: 400, height: 100) + + } + +} diff --git a/Pearcleaner/Settings/Permissions.swift b/Pearcleaner/Settings/Permissions.swift new file mode 100644 index 0000000..1272121 --- /dev/null +++ b/Pearcleaner/Settings/Permissions.swift @@ -0,0 +1,104 @@ +// +// Permissions.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/5/23. +// + +import Foundation +import SwiftUI + +struct PermissionsSettingsTab: View { + @EnvironmentObject var appState: AppState + @State private var diskStatus: Bool = false + @State private var accessStatus: Bool = false + + + + var body: some View { + Form { + VStack(alignment: .leading, spacing: 10) { + + HStack(spacing: 15) { + Image(systemName: "internaldrive") + .resizable() + .scaledToFit() + .frame(width: 20) + + VStack(alignment: .leading, spacing: 5) { + Text("Full Disk") + Text(diskStatus ? "Permission granted" : "Permission not granted") + .font(.footnote) + .foregroundStyle(diskStatus ? .green : .red) + } + + Spacer() + + Button("") { + if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") { + NSWorkspace.shared.open(url) + } + } + .buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View disk permission pane", color: Color("AccentColor"))) + } + .padding() + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color("mode").opacity(0.05)) + ) + + + HStack(spacing: 15) { + Image(systemName: "accessibility") + .resizable() + .scaledToFit() + .frame(width: 20) + + VStack(alignment: .leading, spacing: 5) { + Text("Accessibility") + Text(accessStatus ? "Permission granted" : "Permission not granted") + .font(.footnote) + .foregroundStyle(accessStatus ? .green : .red) + } + + Spacer() + + Button("") { + if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") { + NSWorkspace.shared.open(url) + } + } + .buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View accessibility pane", color: Color("AccentColor"))) + } + .padding() + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color("mode").opacity(0.05)) + ) + + + +// HStack(alignment: .center) { +// Spacer() +// Button("") { +// relaunchApp() +// } +// .buttonStyle(SimpleButtonStyle(icon: "restart", help: "Restart application", color: Color("AccentColor"))) +// Text("Restart") +// Spacer() +// } +// .padding() + + + } + + } + .padding(20) + .frame(width: 400, height: 200) + .onAppear { + diskStatus = checkAndRequestFullDiskAccess(appState: appState, skipAlert: true) + accessStatus = checkAndRequestAccessibilityAccess(appState: appState) + } + } + +} diff --git a/Pearcleaner/Settings/Sentinel.swift b/Pearcleaner/Settings/Sentinel.swift new file mode 100644 index 0000000..8b8e253 --- /dev/null +++ b/Pearcleaner/Settings/Sentinel.swift @@ -0,0 +1,52 @@ +// +// Sentinel.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/9/23. +// + +import Foundation +import SwiftUI + +struct SentinelSettingsTab: View { + @EnvironmentObject var appState: AppState + @AppStorage("settings.sentinel.enable") private var sentinel: Bool = false + + var body: some View { + Form { + VStack { + HStack { + VStack(alignment: .leading, spacing: 5) { + Text("Sentinel Monitor").font(.title2) + Text("Detects when apps are moved to Trash for file removal") + .font(.footnote) + .foregroundStyle(.gray) + } + Spacer() + Toggle(isOn: $sentinel, label: { + }) + .toggleStyle(.switch) + .onChange(of: sentinel) { newValue in + if newValue { + launchctl(load: true) + } else { + launchctl(load: false) + } + } + } + .padding() + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color("mode").opacity(0.05)) + ) + } + + + + } + .padding(20) + .frame(width: 400, height: 100) + + } + +} diff --git a/Pearcleaner/Settings/SettingsWindow.swift b/Pearcleaner/Settings/SettingsWindow.swift new file mode 100644 index 0000000..fd820f3 --- /dev/null +++ b/Pearcleaner/Settings/SettingsWindow.swift @@ -0,0 +1,57 @@ +// +// SettingsWindow.swift +// Pearcleaner +// +// Created by Alin Lupascu on 10/31/23. +// + +import SwiftUI + +struct SettingsView: View { + @EnvironmentObject var appState: AppState + + var body: some View { + + TabView() { + GeneralSettingsTab() + .tabItem { + Label(CurrentTabView.general.title, systemImage: "gear") + } + .tag(CurrentTabView.general) + + PermissionsSettingsTab() + .tabItem { + Label(CurrentTabView.permissions.title, systemImage: "lock") + } + .tag(CurrentTabView.permissions) + + SentinelSettingsTab() + .tabItem { + Label(CurrentTabView.sentinel.title, systemImage: "eye.circle") + } + .tag(CurrentTabView.sentinel) + + UpdateSettingsTab() + .tabItem { + Label(CurrentTabView.update.title, systemImage: "tray.and.arrow.down") + } + .tag(CurrentTabView.update) + + AboutSettingsTab() + .tabItem { + Label(CurrentTabView.about.title, systemImage: "info.circle") + } + .tag(CurrentTabView.about) + + } + + } + +} + + + + + + + diff --git a/Pearcleaner/Settings/Update.swift b/Pearcleaner/Settings/Update.swift new file mode 100644 index 0000000..5a5529b --- /dev/null +++ b/Pearcleaner/Settings/Update.swift @@ -0,0 +1,186 @@ +// +// Update.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/5/23. +// + + +import SwiftUI +import Foundation + +struct Release: Codable { + let id: Int + let tag_name: String + let body: String + let assets: [Asset] +} + +struct Asset: Codable { + let name: String + let url: String + let browser_download_url: String +} + + +struct UpdateSettingsTab: View { + @EnvironmentObject var appState: AppState + @State private var showAlert = false + @State private var showDone = false + @AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1 + + var body: some View { + VStack { + + HStack { + Text("Check for updates every ") + + Text("**\(updateTimeframe)**").foregroundColor(.red) + + Text(updateTimeframe == 1 ? " day" : " days") + Stepper(value: $updateTimeframe, in: 1...7) { + Text("") + } + } + + ScrollView { + VStack() { + ForEach(appState.releases, id: \.id) { release in + VStack(alignment: .leading) { + LabeledDivider(label: "\(release.tag_name)") + Text(release.body) + } + + } + } + .padding() + } + .frame(minHeight: 0, maxHeight: .infinity) + .frame(minWidth: 0, maxWidth: .infinity) + .padding() + + Text("Showing last 3").opacity(0.5).font(.footnote) + + + + HStack(alignment: .center, spacing: 5) { + Spacer() + Button("Check"){ + loadGithubReleases(appState: appState) + }.buttonStyle(BorderedButtonStyle()) + + Button("Force Update"){ + loadGithubReleases(appState: appState, manual: true) + }.buttonStyle(BorderedButtonStyle()) + + Button("GitHub"){ + NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner/releases")!) + }.buttonStyle(BorderedButtonStyle()) + + + Spacer() + } + .padding() + + + + } + .padding(20) + .frame(width: 500, height: 400) + } + +} + + +func loadGithubReleases(appState: AppState, manual: Bool = false) { + let url = URL(string: "https://api.github.com/repos/alienator88/Pearcleaner/releases")! + let request = URLRequest(url: url) +// request.setValue("token \(ghToken)", forHTTPHeaderField: "Authorization") + URLSession.shared.dataTask(with: request) { data, response, error in + if let data = data { + if let decodedResponse = try? JSONDecoder().decode([Release].self, from: data) { + DispatchQueue.main.async { + let lastFiveReleases = Array(decodedResponse.prefix(3)) // Get only the last 3 recent releases + appState.releases = lastFiveReleases + checkForUpdate(appState: appState, manual: manual) + + } + return + } + } + print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")") + }.resume() +} + +func checkForUpdate(appState: AppState, manual: Bool = false) { + guard let latestRelease = appState.releases.first else { return } + let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String + if latestRelease.tag_name > currentVersion ?? "" { + appState.alertType = .update + appState.showAlert = true + } else { + if manual { + appState.alertType = .no_update + appState.showAlert = true + } + } +} + +func downloadUpdate(appState: AppState) { + guard let latestRelease = appState.releases.first else { return } + guard let asset = latestRelease.assets.first else { return } + guard let url = URL(string: asset.url) else { return } + var request = URLRequest(url: url) +// request.setValue("token \(ghToken)", forHTTPHeaderField: "Authorization") + request.setValue("application/octet-stream", forHTTPHeaderField: "Accept") + + let downloadTask = URLSession.shared.downloadTask(with: request) { localURL, urlResponse, error in + guard let localURL = localURL else { return } + + let fileManager = FileManager.default + let destinationURL = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!.appendingPathComponent("Pearcleaner").appendingPathComponent("\(asset.name)") + + do { + if fileManager.fileExists(atPath: destinationURL.path) { + try fileManager.removeItem(at: destinationURL) + } + try fileManager.moveItem(at: localURL, to: destinationURL) + + UnzipAndReplace(DownloadedFileURL: destinationURL.path, appState: appState) { + updateOnMain { + // Restart App + relaunchApp(afterDelay: 1) + } + } + + } catch { + print("Error moving downloaded file: \(error.localizedDescription)") + } + } + + downloadTask.resume() +} + +func UnzipAndReplace(DownloadedFileURL fileURL: String, appState: AppState, completion: @escaping () -> Void = {}) { + let appDirectory = Bundle.main.bundleURL.deletingLastPathComponent().path + let appBundle = Bundle.main.bundleURL.path + let fileManager = FileManager.default + + do { + // Remove the old version of your app + try fileManager.removeItem(atPath: appBundle) + + // Unzip the downloaded update file to your app's bundle path + let process = Process() + process.executableURL = URL(fileURLWithPath: "/usr/bin/unzip") + process.arguments = [fileURL, "-d", appDirectory] + try process.run() + process.waitUntilExit() + + // After unzipping, remove the update file + try fileManager.removeItem(atPath: fileURL) + + } catch { + print("Error updating the app: \(error)") + } + + completion() +} diff --git a/Pearcleaner/Views/AppListItems.swift b/Pearcleaner/Views/AppListItems.swift new file mode 100644 index 0000000..7089964 --- /dev/null +++ b/Pearcleaner/Views/AppListItems.swift @@ -0,0 +1,90 @@ +// +// AppListDetails.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/10/23. +// + +import Foundation +import SwiftUI + +struct AppListItems: View { + @EnvironmentObject var appState: AppState + @State private var isHovered = false + @Environment(\.colorScheme) var colorScheme + let appInfo: AppInfo + var isSelected: Bool { + appState.appInfo == appInfo + } + + var body: some View { + VStack(alignment: .leading, spacing: 5) { + HStack(alignment: .center) { +// if isHovered || isSelected { +// Circle() +// .fill(Color("AccentColor")) +// .frame(width: 10) +// .padding(5) +// } + if let appIcon = appInfo.appIcon { + Image(nsImage: appIcon) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 30, height: 30) + } + VStack(alignment: .leading, spacing: 5) { + Text(appInfo.appName) + .font(.system(size: 12)) + .lineLimit(1) + .truncationMode(.tail) + .padding(.horizontal, 5) + } + + Spacer() + Text(appInfo.appVersion) + .font(.footnote) + .foregroundStyle(Color("mode").opacity(0.5)) + + if isHovered || isSelected { + RoundedRectangle(cornerRadius: 50) + .fill(isSelected ? Color("AccentColor") : Color("mode").opacity(0.5)) + .frame(width: isSelected ? 4 : 2, height: 35) + .padding(.leading, 5) + .offset(x: 20) + } + + } + +// .background( +// RoundedRectangle(cornerRadius: 6) +// .fill(isSelected ? Color("AccentColor").opacity(0.15) : (isHovered ? Color("AccentColor").opacity(0.1) : Color.white.opacity(colorScheme == .dark ? 0.05 : 0.8))) +// .shadow(color: .black.opacity(0.2), radius: 2, x: 0, y: 1) +// .overlay( +// RoundedRectangle(cornerRadius: 6) +// .strokeBorder(Color("AccentColor").opacity(isHovered ? 0.7 : 0.1), lineWidth: 1) +// ) +// ) + +// Rectangle() +// .frame(maxWidth: isSelected ? .infinity : (isHovered ? .infinity : 30), maxHeight: 2) +// .foregroundStyle(Color("AccentColor")) + + } + .padding(.horizontal, 5) + .help(appInfo.appName) + .onHover { hovering in + withAnimation(Animation.easeIn(duration: 0.2)) { + self.isHovered = hovering + } + } + .onTapGesture { + updateOnMain { + appState.appInfo = appInfo + findPathsForApp(appState: appState, appInfo: appState.appInfo) + withAnimation(Animation.easeIn(duration: 0.4)) { + appState.currentView = .files + } + } + } + } +} diff --git a/Pearcleaner/Views/AppListView.swift b/Pearcleaner/Views/AppListView.swift new file mode 100644 index 0000000..6ae1120 --- /dev/null +++ b/Pearcleaner/Views/AppListView.swift @@ -0,0 +1,213 @@ +// +// AppListH.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/5/23. +// + +import Foundation +import SwiftUI + +struct AppListView: View { + @EnvironmentObject var appState: AppState + @AppStorage("settings.general.glass") private var glass: Bool = false + @Binding var search: String + @State private var showSys: Bool = true + @State private var showUsr: Bool = true +// @State private var sidebar: Bool = true + @State private var reload: Bool = false + + var filteredUserApps: [AppInfo] { + if search.isEmpty { + return appState.sortedApps.userApps + } else { + return appState.sortedApps.userApps.filter { $0.appName.localizedCaseInsensitiveContains(search) } + } + } + + var filteredSystemApps: [AppInfo] { + if search.isEmpty { + return appState.sortedApps.systemApps + } else { + return appState.sortedApps.systemApps.filter { $0.appName.localizedCaseInsensitiveContains(search) } + } + } + + var body: some View { + + HStack(alignment: .center, spacing: 0) { + // App List + if appState.sidebar { + ZStack { + HStack(spacing: 0){ + + if reload { + VStack { + Spacer() + ProgressView("Refreshing applications") + Spacer() + } + .frame(width: 300) + .padding(.vertical) + } else { + VStack(alignment: .center) { + + VStack(alignment: .center, spacing: 20) { + SearchBar(search: $search) + } + .padding(.horizontal) + .padding(.top, 20) + .padding(.bottom) + + ScrollView { + + VStack(alignment: .leading) { + + if filteredUserApps.count > 0 { + VStack { + Header(title: "User", count: filteredUserApps.count) + ForEach(filteredUserApps, id: \.self) { appInfo in + AppListItems(appInfo: appInfo) + if appInfo != filteredUserApps.last { + Divider().padding(.horizontal, 5) + } + } + .padding(.bottom) + } + + } + + if filteredSystemApps.count > 0 { + VStack { + Header(title: "System", count: filteredSystemApps.count) + ForEach(filteredSystemApps, id: \.self) { appInfo in + AppListItems(appInfo: appInfo) + if appInfo != filteredSystemApps.last { + Divider().padding(.horizontal, 5) + } + } + } + } + + } + .padding(.horizontal) + + } + .scrollIndicators(.never) + + } + .frame(width: 300) + .padding(.vertical) + } + + + Divider() + } + } + .background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil) + .transition(.move(edge: .leading)) + + Spacer() + } + + + // Details View + VStack(spacing: 0) { + if appState.currentView == .empty { + TopBar(reload: $reload) + AppDetailsEmptyView() + } else if appState.currentView == .files { + TopBar(reload: $reload) + FilesView() + .id(appState.appInfo.id) + } + } +// .padding(.leading, appState.sidebar ? 0 : 10) + .transition(.move(edge: .leading)) + + Spacer() + } + .edgesIgnoringSafeArea(.all) + .onOpenURL(perform: { url in + let deeplinkManager = DeeplinkManager() + deeplinkManager.manage(url: url, appState: appState) + }) + // MARK: Background for whole app + // .background(Color("bg").opacity(1)) + // .background(VisualEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all)) + } +} + + + + + + +struct AppDetailsEmptyView: View { + @Environment(\.colorScheme) var colorScheme + @EnvironmentObject var appState: AppState + @State private var animateGradient: Bool = false + + var body: some View { + VStack() { + + Spacer() + + DropTarget(appState: appState) + + Spacer() + + if appState.isReminderVisible { + Text("􀆔 + Z to undo") + .font(.title2) + .foregroundStyle(Color("AccentColor").opacity(0.5)) + .fontWeight(.medium) + .onAppear { + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + withAnimation { + appState.isReminderVisible = false + } + } + } + Spacer() + } + + Text("Drop an app above or select one from the list to begin") + .font(.title3) + .padding(.bottom, 25) + .opacity(0.5) + } + } +} + + +struct SearchBar: View { + @Binding var search: String + + var body: some View { + HStack { + TextField("Search", text: $search) + .textFieldStyle(SimpleSearchStyle(icon: Image(systemName: "magnifyingglass"),trash: true, text: $search)) + } + .frame(height: 30) + } +} + + +struct Header: View { + let title: String + let count: Int + + var body: some View { + HStack { + Text(title).opacity(0.5) + Spacer() + Text("\(count)") + .frame(minWidth: 30, minHeight: 15) + .padding(2) + .background(Color("mode").opacity(0.1)) + .clipShape(.capsule) + // .clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous)) + } + } +} diff --git a/Pearcleaner/Views/ContentView.swift b/Pearcleaner/Views/ContentView.swift new file mode 100644 index 0000000..3c895c1 --- /dev/null +++ b/Pearcleaner/Views/ContentView.swift @@ -0,0 +1,42 @@ +//// +//// ContentView.swift +//// Pearcleaner +//// +//// Created by Alin Lupascu on 10/31/23. +//// +// +//import SwiftUI +// +//struct ContentView: View { +// @EnvironmentObject var appState: AppState +// @State private var search = "" +// +// var body: some View { +// +// VStack(alignment: .leading) { +//// AppListNav(search: $search) +// AppListH(search: $search) +//// HStack { +//// Image(nsImage: NSApp.applicationIconImage) +//// .imageScale(.large) +//// +//// Text("Pearcleaner") +//// .font(.custom("MontserratAlt1-Light", size: 30, relativeTo: .body)) +//// } +//// .padding() +// +// +// +//// VStack() { +////// AppListView(search: $search) +////// AppListNav(search: $search) +//// } +// } +//// .sheet(isPresented: $appState.showFiles, content: { +//// FilesView() +//// }) +// .alert(isPresented: $appState.showAlert) { presentAlert(appState: appState) } +// +// } +//} +// diff --git a/Pearcleaner/Views/DropTarget.swift b/Pearcleaner/Views/DropTarget.swift new file mode 100644 index 0000000..b2e0f10 --- /dev/null +++ b/Pearcleaner/Views/DropTarget.swift @@ -0,0 +1,168 @@ +// +// DropTarget.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/11/23. +// + +import Foundation +import SwiftUI +import UniformTypeIdentifiers + +struct DropTarget: View, DropDelegate { + @AppStorage("settings.general.ants") private var ants: Bool = false + @ObservedObject var appState: AppState + @State private var shouldFlash = false + private var types: [UTType] = [.fileURL] + @Environment(\.colorScheme) var colorScheme + @State private var phase: CGFloat = 0 + + public init(appState: AppState) { + self.appState = appState + } + + var body: some View { + ZStack { + + FlashingBackground(shouldFlash: $shouldFlash) + + HStack { + Spacer() + + HStack { + Spacer() + + ZStack { + LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing) + .mask(Image("logo") + .resizable() + .scaledToFit()) + } + .frame(width: 500, height: 200) + + Spacer() + + + } + + Spacer() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background { + RoundedRectangle(cornerRadius: 8) + .strokeBorder(LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing), style: StrokeStyle(lineWidth: 3, dash: [10], dashPhase: phase)) + .onAppear { + withAnimation(.linear.speed(0.5).repeat(while: ants, autoreverses: false)) { + if ants { + phase -= 20 + } + } + } + .onChange(of: ants) { newValue in + withAnimation(.linear.speed(0.5).repeat(while: newValue, autoreverses: false)) { + phase -= 20 + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + + } + + + } + .onDrop(of: types, delegate: self) + .padding(20) + + } + + func dropEntered(info: DropInfo) { + DispatchQueue.main.async { + self.ants = true + } + } + + func dropExited(info: DropInfo) { + DispatchQueue.main.async { + self.ants = false + } + } + + func performDrop(info: DropInfo) -> Bool { + + let itemProviders = info.itemProviders(for: [UTType.fileURL]) + + guard itemProviders.count == 1 else { + return false + } + for itemProvider in itemProviders { + itemProvider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil) { item, error in + guard let data = item as? Data else { + dump(error) + return + } + guard let url = URL(dataRepresentation: data, relativeTo: nil) else { + print("Error: Not a valid URL.") + return + } + if url.pathExtension == "app" { + let appInfo = getAppInfo(atPath: url) + + DispatchQueue.main.async { + self.ants = false + appState.appInfo = appInfo! + findPathsForApp(appState: appState, appInfo: appState.appInfo) + appState.currentView = .files + } + } else { + print("Error: Dropped file is not an application bundle") + DispatchQueue.main.async { + self.shouldFlash = true + } + } + + } + } + DispatchQueue.main.async { + self.ants = false + } + return true + } + + +} + + +struct FlashingBackground: View { + @Binding var shouldFlash: Bool + + var body: some View { + GeometryReader { geometry in + Rectangle() + .fill(shouldFlash ? Color.red : Color.clear) + .cornerRadius(8) + .padding() + .opacity(shouldFlash ? 0.5 : 0) + .animation(.easeInOut(duration: 0.2).repeatCount(1, autoreverses: true), value: shouldFlash) + .onChange(of: shouldFlash) { newValue in + if newValue { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { + shouldFlash = false + } + } + } + .ignoresSafeArea() + .frame(width: geometry.size.width, height: geometry.size.height) + } + } +} + + + +extension Animation { + func `repeat`(while expression: Bool, autoreverses: Bool = true) -> Animation { + if expression { + return self.repeatForever(autoreverses: autoreverses) + } else { + return self + } + } +} diff --git a/Pearcleaner/Views/FilesView.swift b/Pearcleaner/Views/FilesView.swift new file mode 100644 index 0000000..a1917c5 --- /dev/null +++ b/Pearcleaner/Views/FilesView.swift @@ -0,0 +1,443 @@ +// +// FilesView.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/1/23. +// + +import Foundation +import SwiftUI + +struct FilesView: View { + @EnvironmentObject var appState: AppState + @State private var appSize: String = "" + @State private var showDetails: Bool = false + @State private var showPop: Bool = false + @State private var itemDetails: [(size: String, icon: Image?)] = [] + @Environment(\.colorScheme) var colorScheme + + var body: some View { + VStack(alignment: .center) { + if !self.showDetails { + VStack { + Spacer() + ProgressView("Finding application files..") + Spacer() + } + .transition(.opacity) + } else { + VStack() { + + // Main Group + HStack() { + //icon + if let appIcon = appState.appInfo.appIcon { + Image(nsImage: appIcon) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 100, height: 100) + .padding(.leading) + } + //app title, size and items + VStack(alignment: .center) { + HStack(alignment: .center) { + VStack(alignment: .leading, spacing: 5){ + HStack { + Text("\(appState.appInfo.appName)").font(.title).fontWeight(.bold) +// .foregroundStyle(Color("AccentColor")) + Text("•").foregroundStyle(Color("AccentColor")) + Text("\(appState.appInfo.appVersion)").font(.title3) +// .foregroundStyle(.gray.opacity(0.8)) + } + Text("\(appState.appInfo.bundleIdentifier)").font(.title3) + .foregroundStyle((.gray.opacity(0.8))) + } + + Spacer() + + Text("\(appSize)").font(.title).fontWeight(.bold) +// .foregroundStyle(Color("AccentColor")) + } + + + Divider().padding(.bottom, 7) + + HStack{ + Text("Application files and folders") + .font(.callout) +// .foregroundStyle(Color("AccentColor")) + .opacity(0.8) + Spacer() + Text("\(appState.paths.count > 1 ? "\(appState.paths.count) items" : "\(appState.paths.count) item")").font(.callout) +// .foregroundStyle(Color("AccentColor").opacity(0.7)) + .underline() + } + if appState.appInfo.appName.count < 5 { + HStack(alignment: .center) { + Button(""){ + showPop = true + } + .buttonStyle(SimpleButtonStyle(icon: "exclamationmark.triangle.fill", help: "Warning", color: .red)) + .popover(isPresented: $showPop, arrowEdge: .top) { + VStack() { + Text("Pearcleaner searches for files with a combination of bundle id and app name.\n**\(appState.appInfo.appName)** has a common or short app name so there might be unrelated files found.\nPlease check the list thoroughly before uninstalling.") + .padding(20) + .font(.title2) + } + + } + Text("Read caution message") + .foregroundStyle(Color.red) + + Spacer() + } + .padding(.top) + .onTapGesture { + showPop = true + } + } + + + } + .padding(20) + } + .padding([.horizontal, .bottom]) + .background( + RoundedRectangle(cornerRadius: 8) +// .strokeBorder(Color("AccentColor"), lineWidth: 0.5) + .fill(Color("mode").opacity(colorScheme == .dark ? 0.05 : 0.05)) +// .background( +// RoundedRectangle(cornerRadius: 8) +// .strokeBorder(Color("AccentColor").opacity(colorScheme == .dark ? 0.1 : 0.1), lineWidth: 1) +// ) + ) + + + + ScrollView { + VStack { + ForEach(Array(zip(appState.paths, itemDetails)), id: \.0) { path, details in + if let firstPath = appState.paths.first, path == firstPath { + FileDetailsItem(size: details.size, icon: details.icon, path: path) + .padding(.trailing) + Divider().padding(.leading, 40).padding(.trailing) + } else { + VStack { + FileDetailsItem(size: details.size, icon: details.icon, path: path) + if path != appState.paths.last { + Divider().padding(.leading, 40) + } + } + .padding(.leading, 47).padding(.trailing) + + + } + } + } + } + .padding() + + HStack() { + Spacer() + +// if appState.trashLaunch { +// Button("Close") { +// Task { +// NSApp.terminate(nil) +// exit(0) +// } +// } +// .buttonStyle(WindowActionButton(action: .cancel)) +// } + + + Button("Uninstall") { + Task { + updateOnMain { + appState.appInfo = AppInfo.empty + appState.currentView = .empty + } + let selectedItemsArray = Array(appState.selectedItems).filter { !$0.path.contains(".Trash") } + killApp(appId: appState.appInfo.bundleIdentifier) { + moveFilesToTrash(at: selectedItemsArray) { + withAnimation { + appState.isReminderVisible.toggle() + } + refreshAppList(appState.appInfo) + } + } + } + } + .disabled(appState.selectedItems.isEmpty) + .buttonStyle(WindowActionButton(action: .accept)) + } +// .padding(.top) + + } + .transition(.opacity) + .padding(20) + + } + + } + .frame(minWidth: 700) + .onAppear { + Task { + calculateFileDetails() + } + } + } + + + func calculateFileDetails() { + if appState.paths.count != 0 { + itemDetails = Array(repeating: (size: "", icon: nil), count: appState.paths.count) + Task { + for (index, path) in appState.paths.enumerated() { + var size = "" + var icon: Image? = nil + + if let appSize = totalSizeOnDisk(for: path) { + size = "\(appSize)" + } else { + print("Error calculating the total size on disk for item \(index).") + } + if let folderIcon = getIconForFileOrFolder(atPath: path) { + icon = folderIcon + } + itemDetails[index] = (size: size, icon: icon) + } + if let appSize = totalSizeOnDisk(for: appState.paths) { + self.appSize = "\(appSize)" + self.showDetails = true + } else { + print("Error calculating the total size on disk.") + } + } + } else { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + calculateFileDetails() + } + } + } + + + func refreshAppList(_ appInfo: AppInfo) { + let sortedApps = getSortedApps() + appState.sortedApps.userApps = [] + appState.sortedApps.systemApps = [] + appState.sortedApps.userApps = sortedApps.userApps + appState.sortedApps.systemApps = sortedApps.systemApps + } +} + + + +struct FileDetailsItem: View { + @EnvironmentObject var appState: AppState + let size: String + let icon: Image? + let path: URL + + var body: some View { + HStack(alignment: .center, spacing: 20) { + Toggle("", isOn: Binding( + get: { self.appState.selectedItems.contains(self.path) }, + set: { isChecked in + if isChecked { + self.appState.selectedItems.insert(self.path) + if self.path == appState.appInfo.path { + self.appState.paths.forEach { self.appState.selectedItems.insert($0) } + } + } else { + self.appState.selectedItems.remove(self.path) + if self.path == appState.appInfo.path { + self.appState.selectedItems.forEach { self.appState.selectedItems.remove($0) } + } + } + } + )) + .disabled(self.path.path.contains(".Trash")) + + if let appIcon = icon { + appIcon + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 30, height: 30) + } + VStack(alignment: .leading, spacing: 5) { + Text(path.lastPathComponent) + .font(.title3) + .lineLimit(1) + .truncationMode(.tail) + .help(path.lastPathComponent) + Text(path.path) + .font(.footnote) + .lineLimit(1) + .truncationMode(.tail) + .opacity(0.5) +// .foregroundStyle(Color("AccentColor")) + .help(path.path) + } + + Spacer() + if size.isEmpty { + ProgressView().controlSize(.small) + } else { + Text(size) + } + + + Button("") { + NSWorkspace.shared.selectFile(path.path, inFileViewerRootedAtPath: path.deletingLastPathComponent().path) + } + .buttonStyle(SimpleButtonStyle(icon: "folder.fill", help: "Show in Finder", color: Color("AccentColor"))) + + } + .background( + RoundedRectangle(cornerRadius: 10) + .fill(Color.white.opacity(0)) + ) + } +} + + +func writeLog(string: String) { + let fileManager = FileManager.default + let home = fileManager.homeDirectoryForCurrentUser.path + let logFilePath = "\(home)/Downloads/log.txt" + + // Check if the log file exists, and create it if it doesn't + if !fileManager.fileExists(atPath: logFilePath) { + if !fileManager.createFile(atPath: logFilePath, contents: nil, attributes: nil) { + print("Failed to create the log file.") + return + } + } + + do { + if let fileHandle = FileHandle(forWritingAtPath: logFilePath) { + let ns = "\(string)\n" + fileHandle.seekToEndOfFile() + fileHandle.write(ns.data(using: .utf8)!) + fileHandle.closeFile() + } else { + print("Error opening file for appending") + } + } +} + +//struct FilesView: View { +// @EnvironmentObject var appState: AppState +// @State private var appSize: String = "" +// @State private var showDetails: Bool = false +// @State private var itemDetails: [(size: String, icon: Image?)] = [] +// +// var body: some View { +// VStack(alignment: .center) { +// if !self.showDetails { +// ProgressView("Finding application files..") +// } else { +// VStack() { +// HStack() { +// Text("\(appState.paths.count > 1 ? "\(appState.paths.count) files found" : "\(appState.paths.count) file found")") +// Text("•") +// Text("\(appSize)") +// } +// .padding() +// +// if appState.appInfo.appName.count < 5 { +// Text("Short or common word app name, there might be unrelated files found") +// .font(.footnote) +// .foregroundStyle(.red) +// } +// +// ScrollView { +// ForEach(Array(zip(appState.paths, itemDetails)), id: \.0) { path, details in +// FileDetailsItem(size: details.size, icon: details.icon, path: path) +// } +// } +// .frame(width: 500) +// +// Button("Remove") { +// Task { +// updateOnMain { +// appState.appInfo = AppInfo.empty +// } +// let selectedItemsArray = Array(appState.selectedItems) +// killApp(appId: appState.appInfo.bundleIdentifier) { +// moveFilesToTrash(at: selectedItemsArray) { +// refreshAppList(appState.appInfo) +// } +// } +// } +// } +// .disabled(appState.selectedItems.isEmpty) +// } +// .padding() +// +// } +// +// } +// .frame(minWidth: 500) +// .onAppear { +// Task { +// // appState.appInfo = appInfo +// // findPathsForApp(appState: appState, appInfo: appState.appInfo) +// calculateFileDetails() +// } +// } +// } +// +// +// func calculateFileDetails() { +// if appState.paths.count != 0 { +// itemDetails = Array(repeating: (size: "", icon: nil), count: appState.paths.count) +// +// Task { +// for (index, path) in appState.paths.enumerated() { +// var size = "" +// var icon: Image? = nil +// +// if let appSize = totalSizeOnDisk(for: path) { +// size = "\(appSize)" +// } else { +// print("Error calculating the total size on disk for item \(index).") +// } +// +// if let folderIcon = getIconForFileOrFolder(atPath: path) { +// icon = folderIcon +// } +// +// itemDetails[index] = (size: size, icon: icon) +// +// +// +// } +// +// if let appSize = totalSizeOnDisk(for: appState.paths) { +// self.appSize = "\(appSize)" +// // updateOnMain { +// // appState.doneLoading = true +// // } +// self.showDetails = true +// // appState.doneLoading = true +// } else { +// print("Error calculating the total size on disk.") +// } +// } +// } else { +// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { +// calculateFileDetails() +// } +// } +// } +// +// func refreshAppList(_ appInfo: AppInfo) { +// let sortedApps = getSortedApps() +// appState.sortedApps.userApps = [] +// appState.sortedApps.systemApps = [] +// appState.sortedApps.userApps = sortedApps.userApps +// appState.sortedApps.systemApps = sortedApps.systemApps +// } +//} diff --git a/Pearcleaner/Views/TopBar.swift b/Pearcleaner/Views/TopBar.swift new file mode 100644 index 0000000..8ff1c75 --- /dev/null +++ b/Pearcleaner/Views/TopBar.swift @@ -0,0 +1,104 @@ +// +// TopBar.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/10/23. +// + +import Foundation +import SwiftUI + +struct TopBar: View { +// @Binding var sidebar: Bool + @Binding var reload: Bool + @AppStorage("displayMode") var displayMode: DisplayMode = .system + @AppStorage("settings.general.glass") private var glass: Bool = false + @EnvironmentObject var appState: AppState + + var body: some View { + HStack(alignment: .center, spacing: 20) { + + HStack(alignment: .center, spacing: 5) { +// Button("") { +// withAnimation(.easeInOut(duration: 0.5)) { +// appState.sidebar.toggle() +// if appState.sidebar { +// appState.winWidth += 300 +// } else { +// appState.winWidth -= 300 +// } +// } +// } +// .buttonStyle(SimpleButtonStyle(icon: "sidebar.left", help: "Toggle Sidebar", color: Color("AccentColor"))) + + + Button("") { + withAnimation(.easeInOut(duration: 0.5)) { + // Refresh Apps list + reload.toggle() + let sortedApps = getSortedApps() + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + appState.sortedApps.userApps = sortedApps.userApps + appState.sortedApps.systemApps = sortedApps.systemApps + reload.toggle() + } + + } + } + .buttonStyle(SimpleButtonStyle(icon: "arrow.circlepath", help: "Refresh app list", color: Color("AccentColor"))) + + Button("") { + withAnimation(.easeInOut(duration: 0.5)) { + openTrash() + } + } + .buttonStyle(SimpleButtonStyle(icon: "trash", help: "Open Trash", color: Color("AccentColor"))) + } + + Spacer() + + + + if appState.currentView != .empty { + Button("") { + withAnimation(.easeInOut(duration: 0.5)) { + appState.currentView = .empty + appState.appInfo = AppInfo.empty + } + } + .buttonStyle(SimpleButtonStyle(icon: "house", help: "Home", color: Color("AccentColor"))) + } + + + + + Spacer() + + HStack(alignment: .center, spacing: 5) { + Button("") { + withAnimation(.easeInOut(duration: 0.5)) { + glass.toggle() + } + } + .buttonStyle(SimpleButtonStyle(icon: glass ? "circle.dashed" : "circle.dashed.inset.filled", help: "Toggle transparency", color: Color("AccentColor"))) + + Button("") { + withAnimation(.easeInOut(duration: 0.5)) { + if displayMode.colorScheme == .dark { + displayMode.colorScheme = .light + } else if displayMode.colorScheme == .light { + displayMode.colorScheme = .dark + } else { + displayMode.colorScheme = .dark + } + } + } + .buttonStyle(SimpleButtonStyle(icon: displayMode.colorScheme == .dark ? "sun.max.fill" : "moon.fill", help: "Toggle appearance", color: Color("AccentColor"))) + } + + + } + .padding(.horizontal, 20) + .padding(.top, 30) + } +} diff --git a/Pearcleaner/Views/TrashView.swift b/Pearcleaner/Views/TrashView.swift new file mode 100644 index 0000000..7affbcc --- /dev/null +++ b/Pearcleaner/Views/TrashView.swift @@ -0,0 +1,19 @@ +// +// TrashView.swift +// Pearcleaner +// +// Created by Alin Lupascu on 11/11/23. +// + +import Foundation +import SwiftUI + +struct TrashView: View { + @EnvironmentObject var appState: AppState + + var body: some View { + VStack() { + Text("Trash view my boi") + } + } +} diff --git a/PearcleanerSentinel/PearcleanerSentinel.entitlements b/PearcleanerSentinel/PearcleanerSentinel.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/PearcleanerSentinel/PearcleanerSentinel.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/PearcleanerSentinel/main.swift b/PearcleanerSentinel/main.swift new file mode 100644 index 0000000..abe12d6 --- /dev/null +++ b/PearcleanerSentinel/main.swift @@ -0,0 +1,285 @@ +// +// main.swift +// PearcleanerSentinel +// +// Created by Alin Lupascu on 11/9/23. +// + +import Foundation +import FileWatcher +import AppKit + +// Start Trash monitoring +fileWatcher() + +// Keep alive indefinitely +while true { + sleep(1) +} + +func fileWatcher() { + let home = FileManager.default.homeDirectoryForCurrentUser.path + let filewatcher = FileWatcher(["\(home)/.Trash"]) + filewatcher.queue = DispatchQueue.global() + filewatcher.callback = { event in + checkApp(file: event.path) + } + filewatcher.start() +} + +func checkApp(file: String) { + let app = URL(fileURLWithPath: file) + let appExt = app.pathExtension + if appExt == "app" { + if FileManager.default.isInTrash(app) { + NSWorkspace.shared.open(URL(string: "pear://com.alienator88.Pearcleaner?path=\(file)")!) + } + } +} + +// --- Trash Relationship --- +extension FileManager { + public func isInTrash(_ file: URL) -> Bool { + var relationship: URLRelationship = .other + do { + try getRelationship(&relationship, of: .trashDirectory, in: .userDomainMask, toItemAt: file) + return relationship == .contains + } catch { + return false + } + } +} + + + + + + +// For testing and outputing logging to file from cmd line tool +func writeLog(string: String) { + let fileManager = FileManager.default + let home = fileManager.homeDirectoryForCurrentUser.path + let logFilePath = "\(home)/Downloads/monitor.txt" + + // Check if the log file exists, and create it if it doesn't + if !fileManager.fileExists(atPath: logFilePath) { + if !fileManager.createFile(atPath: logFilePath, contents: nil, attributes: nil) { + print("Failed to create the log file.") + return + } + } + + do { + if let fileHandle = FileHandle(forWritingAtPath: logFilePath) { + let ns = "\(string)\n" + fileHandle.seekToEndOfFile() + fileHandle.write(ns.data(using: .utf8)!) + fileHandle.closeFile() + } else { + print("Error opening file for appending") + } + } +} + + + + + + + + + + + + + +// let trashContents = getTrashContents() +// if !trashContents.isEmpty && trashContents.contains(event.path) { +// NSWorkspace.shared.open(URL(string: "pear://com.alienator88.Pearcleaner?path=\(event.path)")!) +// } + +//func getTrashContents() -> [String] { +// let fileManager = FileManager.default +// let trashURLs = fileManager.urls(for: .trashDirectory, in: .userDomainMask) +// do { +// let trashContents = try fileManager.contentsOfDirectory(at: trashURLs.first!, includingPropertiesForKeys: nil, options: []) +// let appFiles = trashContents.filter { $0.pathExtension == "app" } +// writeLog(string: appFiles.first!.path) +// +// return appFiles.map { $0.path } +// } catch { +// print("Failed to get contents of trash directory: \(error)") +// return [] +// } +//} + +//func hasAccessToTrashFolder() -> Bool { +// let fileManager = FileManager.default +// let trashURLs = fileManager.urls(for: .trashDirectory, in: .userDomainMask) +// +// if let trashURL = trashURLs.first { +// return fileManager.isReadableFile(atPath: trashURL.path) && fileManager.isWritableFile(atPath: trashURL.path) +// } +// +// return false +//} + +//if hasAccessToTrashFolder() { +// writeLog(string: "Your tool has access to the Trash folder.") +// print("Your tool has access to the Trash folder.") +//} else { +// if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") { +// NSWorkspace.shared.open(url) +// } +// writeLog(string: "Your tool does not have access to the Trash folder.") +// print("Your tool does not have access to the Trash folder.") +//} + + +//var dirWatcher: DirMonitor? +//func fileW2() { +// let home = FileManager.default.homeDirectoryForCurrentUser.path +// let url = URL(fileURLWithPath: "\(home)/.Trash") +// dirWatcher = DirMonitor(dir: url, queue: .global()) +// if dirWatcher?.start() == true { +// NSLog("Started directory monitoring") +// } else { +// NSLog("Failed to start directory monitoring") +// } +//} +// +//class DirMonitor { +// +// init(dir: URL, queue: DispatchQueue) { +// self.dir = dir +// self.queue = queue +// } +// +// deinit { +// // The stream has a reference to us via its `info` pointer. If the +// // client releases their reference to us without calling `stop`, that +// // results in a dangling pointer. We detect this as a programming error. +// // There are other approaches to take here (for example, messing around +// // with weak, or forming a retain cycle that’s broken on `stop`), but +// // this approach: +// // +// // * Has clear rules +// // * Is easy to implement +// // * Generate a sensible debug message if the client gets things wrong +// precondition(self.stream == nil, "released a running monitor") +// // I added this log line as part of my testing of the deallocation path. +// NSLog("did deinit") +// } +// +// let dir: URL +// let queue: DispatchQueue +// +// private var stream: FSEventStreamRef? = nil +// +// func start() -> Bool { +// precondition(self.stream == nil, "started a running monitor") +// +// // Set up our context. +// // +// // `FSEventStreamCallback` is a C function, so we pass `self` to the +// // `info` pointer so that it get call our `handleUnsafeEvents(…)` +// // method. This involves the standard `Unmanaged` dance: +// // +// // * Here we set `info` to an unretained pointer to `self`. +// // * Inside the function we extract that pointer as `obj` and then use +// // that to call `handleUnsafeEvents(…)`. +// +// var context = FSEventStreamContext() +// context.info = Unmanaged.passUnretained(self).toOpaque() +// +// // Create the stream. +// // +// // In this example I wanted to show how to deal with raw string paths, +// // so I’m not taking advantage of `kFSEventStreamCreateFlagUseCFTypes` +// // or the even cooler `kFSEventStreamCreateFlagUseExtendedData`. +// +// guard let stream = FSEventStreamCreate(nil, { (stream, info, numEvents, eventPaths, eventFlags, eventIds) in +// let obj = Unmanaged.fromOpaque(info!).takeUnretainedValue() +// obj.handleUnsafeEvents(numEvents: numEvents, eventPaths: eventPaths, eventFlags: eventFlags, eventIDs: eventIds) +// }, +// &context, +// [self.dir.path as NSString] as NSArray, +// UInt64(kFSEventStreamEventIdSinceNow), +// 1.0, +// FSEventStreamCreateFlags(kFSEventStreamCreateFlagNone) +// ) else { +// return false +// } +// self.stream = stream +// +// // Now that we have a stream, schedule it on our target queue. +// +// FSEventStreamSetDispatchQueue(stream, queue) +// guard FSEventStreamStart(stream) else { +// FSEventStreamInvalidate(stream) +// self.stream = nil +// return false +// } +// return true +// } +// +// private func handleUnsafeEvents(numEvents: Int, eventPaths: UnsafeMutableRawPointer, eventFlags: UnsafePointer, eventIDs: UnsafePointer) { +// // This takes the low-level goo from the C callback, converts it to +// // something that makes sense for Swift, and then passes that to +// // `handle(events:…)`. +// // +// // Note that we don’t need to do any rebinding here because this data is +// // coming C as the right type. +// let pathsBase = eventPaths.assumingMemoryBound(to: UnsafePointer.self) +// let pathsBuffer = UnsafeBufferPointer(start: pathsBase, count: numEvents) +// let flagsBuffer = UnsafeBufferPointer(start: eventFlags, count: numEvents) +// let eventIDsBuffer = UnsafeBufferPointer(start: eventIDs, count: numEvents) +// // As `zip(_:_:)` only handles two sequences, I map over the index. +// let events = (0.. (url: URL, flags: FSEventStreamEventFlags, eventIDs: FSEventStreamEventId) in +// let path = pathsBuffer[i] +// // We set `isDirectory` to true because we only generate directory +// // events (that is, we don’t pass +// // `kFSEventStreamCreateFlagFileEvents` to `FSEventStreamCreate`. +// // This is generally the best way to use FSEvents, but if you decide +// // to take advantage of `kFSEventStreamCreateFlagFileEvents` then +// // you’ll need to code to `isDirectory` correctly. +// let url: URL = URL(fileURLWithFileSystemRepresentation: path, isDirectory: true, relativeTo: nil) +// return (url, flagsBuffer[i], eventIDsBuffer[i]) +// } +// self.handle(events: events) +// } +// +// private func handle(events: [(url: URL, flags: FSEventStreamEventFlags, eventIDs: FSEventStreamEventId)]) { +// // In this example we just print the events with get, prefixed by a +// // count so that we can see the batching in action. +// NSLog("%d", events.count) +// for (url, flags, eventID) in events { +// NSLog("%16x %8x %@", eventID, flags, url.path) +// } +// for (url, flags, _) in events { +// if flags & FSEventStreamEventFlags(kFSEventStreamEventFlagItemRemoved) != 0 { +// NSLog("Removed: \(url.path)") +// } +// if flags & FSEventStreamEventFlags(kFSEventStreamEventFlagItemCreated) != 0 { +// NSLog("Created: \(url.path)") +// } +// } +// getTrashContents() +// } +// +// func stop() { +// guard let stream = self.stream else { +// return // We accept redundant calls to `stop`. +// } +// FSEventStreamStop(stream) +// FSEventStreamInvalidate(stream) +// self.stream = nil +// } +// +// func getTrashContents() { +// let fileManager = FileManager.default +// let trashURLs = fileManager.urls(for: .trashDirectory, in: .userDomainMask) +// let trashContents = try? fileManager.contentsOfDirectory(at: trashURLs.first!, includingPropertiesForKeys: nil, options: []) +// print(trashContents as Any) +// } +//} diff --git a/README.md b/README.md new file mode 100644 index 0000000..708a6f1 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Pearcleaner + Open-source macOS app cleaner