v3.0.0
@@ -19,7 +19,6 @@
|
||||
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 */; };
|
||||
@@ -32,13 +31,11 @@
|
||||
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 */; };
|
||||
C7A9CE472B89164700EB6E78 /* Authorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A9CE462B89164700EB6E78 /* Authorization.swift */; };
|
||||
C7ACADE62B92A737000B5845 /* Features.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7ACADE52B92A737000B5845 /* Features.swift */; };
|
||||
C7CF47242B3B3F1700979C5F /* WindowSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7CF47232B3B3F1700979C5F /* WindowSettings.swift */; };
|
||||
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 */; };
|
||||
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 */
|
||||
|
||||
@@ -76,7 +73,6 @@
|
||||
C72893112AFD51EA00C8C1CD /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||
C76D08472AF83C3F00D07867 /* Update.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Update.swift; sourceTree = "<group>"; };
|
||||
C76D08492AF83C6E00D07867 /* General.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = General.swift; sourceTree = "<group>"; };
|
||||
C76D084B2AF83C9D00D07867 /* Permissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Permissions.swift; sourceTree = "<group>"; };
|
||||
C76D08502AF850F300D07867 /* About.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = About.swift; sourceTree = "<group>"; };
|
||||
C76D08542AF89CDE00D07867 /* AppListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppListView.swift; sourceTree = "<group>"; };
|
||||
C77B90002AF18E2E009CC655 /* Pearcleaner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Pearcleaner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -93,13 +89,11 @@
|
||||
C7A27E7F2AFD70DD00166168 /* PearcleanerSentinel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PearcleanerSentinel.entitlements; sourceTree = "<group>"; };
|
||||
C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.alienator88.PearcleanerSentinel.plist; sourceTree = "<group>"; };
|
||||
C7A9CE462B89164700EB6E78 /* Authorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Authorization.swift; sourceTree = "<group>"; };
|
||||
C7ACADE52B92A737000B5845 /* Features.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features.swift; sourceTree = "<group>"; };
|
||||
C7CF47232B3B3F1700979C5F /* WindowSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowSettings.swift; sourceTree = "<group>"; };
|
||||
C7D31D452AFDA90C00C7ED9E /* Sentinel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sentinel.swift; sourceTree = "<group>"; };
|
||||
C7D31D472AFEB23700C7ED9E /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.swift; sourceTree = "<group>"; };
|
||||
C7D31D492AFEB26700C7ED9E /* AppListItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppListItems.swift; sourceTree = "<group>"; };
|
||||
C7D31D502AFF00F300C7ED9E /* Locations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locations.swift; sourceTree = "<group>"; };
|
||||
C7D31D542B008CB900C7ED9E /* Shapes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shapes.swift; sourceTree = "<group>"; };
|
||||
C7D31D582B00A49300C7ED9E /* DropTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropTarget.swift; sourceTree = "<group>"; };
|
||||
C7F539372AF60865007DF1B2 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -142,9 +136,9 @@
|
||||
C72893042AFD42E600C8C1CD /* DeepLink.swift */,
|
||||
C77B901B2AF193A3009CC655 /* Styles.swift */,
|
||||
C7D31D502AFF00F300C7ED9E /* Locations.swift */,
|
||||
C7D31D542B008CB900C7ED9E /* Shapes.swift */,
|
||||
C7CF47232B3B3F1700979C5F /* WindowSettings.swift */,
|
||||
C7A9CE462B89164700EB6E78 /* Authorization.swift */,
|
||||
C7ACADE52B92A737000B5845 /* Features.swift */,
|
||||
);
|
||||
path = Logic;
|
||||
sourceTree = "<group>";
|
||||
@@ -171,8 +165,6 @@
|
||||
children = (
|
||||
C77B901D2AF1A9DB009CC655 /* SettingsWindow.swift */,
|
||||
C76D08492AF83C6E00D07867 /* General.swift */,
|
||||
C76D084B2AF83C9D00D07867 /* Permissions.swift */,
|
||||
C7D31D452AFDA90C00C7ED9E /* Sentinel.swift */,
|
||||
C76D08472AF83C3F00D07867 /* Update.swift */,
|
||||
C76D08502AF850F300D07867 /* About.swift */,
|
||||
);
|
||||
@@ -230,7 +222,6 @@
|
||||
C7D31D472AFEB23700C7ED9E /* TopBar.swift */,
|
||||
C7045A292B03FAF000376976 /* TopBarMini.swift */,
|
||||
C7D31D492AFEB26700C7ED9E /* AppListItems.swift */,
|
||||
C7D31D582B00A49300C7ED9E /* DropTarget.swift */,
|
||||
C7045A272B03E71D00376976 /* MiniMode.swift */,
|
||||
C71848432B8D2D600046CB13 /* ZombieView.swift */,
|
||||
);
|
||||
@@ -358,23 +349,20 @@
|
||||
C7045A322B068AD700376976 /* NewWin.swift in Sources */,
|
||||
C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */,
|
||||
C77B901A2AF1938F009CC655 /* Logic.swift in Sources */,
|
||||
C7D31D462AFDA90C00C7ED9E /* Sentinel.swift in Sources */,
|
||||
C7D31D592B00A49300C7ED9E /* DropTarget.swift in Sources */,
|
||||
C7045A2A2B03FAF000376976 /* TopBarMini.swift in Sources */,
|
||||
C77B901C2AF193A3009CC655 /* Styles.swift in Sources */,
|
||||
C7045A282B03E71D00376976 /* MiniMode.swift in Sources */,
|
||||
C72893052AFD42E600C8C1CD /* DeepLink.swift in Sources */,
|
||||
C71848442B8D2D600046CB13 /* ZombieView.swift in Sources */,
|
||||
C76D084C2AF83C9D00D07867 /* Permissions.swift in Sources */,
|
||||
C76D084A2AF83C6E00D07867 /* General.swift in Sources */,
|
||||
C77B90042AF18E2E009CC655 /* PearcleanerApp.swift in Sources */,
|
||||
C7D31D552B008CB900C7ED9E /* Shapes.swift in Sources */,
|
||||
C7045A362B068DD700376976 /* PermView.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 */,
|
||||
C7ACADE62B92A737000B5845 /* Features.swift in Sources */,
|
||||
C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */,
|
||||
C76D08552AF89CDE00D07867 /* AppListView.swift in Sources */,
|
||||
C7A9CE472B89164700EB6E78 /* Authorization.swift in Sources */,
|
||||
@@ -551,7 +539,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BK8443AXLU;
|
||||
@@ -569,7 +557,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 2.7;
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -586,7 +574,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BK8443AXLU;
|
||||
@@ -604,7 +592,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 2.7;
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
||||
@@ -46,12 +46,6 @@ struct AppCommands: Commands {
|
||||
updateOnMain {
|
||||
appState.reload.toggle()
|
||||
}
|
||||
// let sortedApps = getSortedApps()
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
// appState.sortedApps.userApps = sortedApps.userApps
|
||||
// appState.sortedApps.systemApps = sortedApps.systemApps
|
||||
// appState.reload.toggle()
|
||||
// }
|
||||
}
|
||||
} label: {
|
||||
Text("Refresh Apps")
|
||||
@@ -86,6 +80,8 @@ struct AppCommands: Commands {
|
||||
Label("Undo Removal", systemImage: "clear")
|
||||
}
|
||||
.keyboardShortcut("z", modifiers: .command)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ class AppState: ObservableObject
|
||||
|
||||
self.zombieFile = ZombieFile(
|
||||
id: UUID(),
|
||||
// files: [],
|
||||
fileSize: [:],
|
||||
fileIcon: [:]
|
||||
)
|
||||
@@ -86,7 +85,6 @@ struct AppInfo: Identifiable, Equatable, Hashable {
|
||||
|
||||
struct ZombieFile: Identifiable, Equatable, Hashable {
|
||||
let id: UUID
|
||||
// var files: [URL]
|
||||
var fileSize: [URL:Int64]
|
||||
var fileIcon: [URL:NSImage?]
|
||||
var totalSize: Int64
|
||||
@@ -184,78 +182,4 @@ enum DisplayMode: Int, CaseIterable {
|
||||
}
|
||||
|
||||
|
||||
//class ProgressManager: ObservableObject {
|
||||
// @Published var progress: Double = 0.0
|
||||
// @Published var total: Double = 0.0
|
||||
// @Published var status: String = "Ready"
|
||||
//
|
||||
// func setTotal(_ total: Double) {
|
||||
// DispatchQueue.main.async {
|
||||
// self.total = total
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func updateProgress() {
|
||||
// DispatchQueue.main.async {
|
||||
// self.progress = min(max(0.0, self.progress + 1.0), Double(self.total))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func updateStatus(status: String) {
|
||||
// DispatchQueue.main.async {
|
||||
// self.status = status
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func resetProgress() {
|
||||
// DispatchQueue.main.async {
|
||||
// self.progress = 0.0
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
//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
|
||||
//]
|
||||
|
||||
@@ -35,36 +35,6 @@ class DeeplinkManager {
|
||||
let pathURL = URL(fileURLWithPath: path)
|
||||
let appInfo = getAppInfo(atPath: pathURL)
|
||||
showAppInFiles(appInfo: appInfo!, mini: mini, appState: appState, locations: locations, showPopover: $showPopover)
|
||||
|
||||
// showPopover = false
|
||||
// updateOnMain {
|
||||
// appState.appInfo = .empty
|
||||
// if let storedAppInfo = appState.appInfoStore.first(where: { $0.path == appInfo?.path }) {
|
||||
// appState.appInfo = storedAppInfo
|
||||
//// appState.paths = storedAppInfo.fileSize.keys.map { $0 }//storedAppInfo.files
|
||||
// appState.selectedItems = Set(storedAppInfo.files)
|
||||
// withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
// if self.mini {
|
||||
// self.showPopover.toggle()
|
||||
// } else {
|
||||
// appState.currentView = .files
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // Handle the case where the appInfo is not found in the store
|
||||
// printOS("AppInfo not found in the cached store, searching again")
|
||||
// appState.appInfo = .empty
|
||||
// appState.appInfo = appInfo!
|
||||
// findPathsForApp(appInfo: appInfo!, appState: appState, locations: locations)
|
||||
// withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
// if self.mini {
|
||||
// self.showPopover.toggle()
|
||||
// } else {
|
||||
// appState.currentView = .files
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
printOS("No path query parameter found in the URL")
|
||||
}
|
||||
@@ -77,45 +47,6 @@ class DeeplinkManager {
|
||||
func handleAppBundle(url: URL, appState: AppState, locations: Locations) {
|
||||
let appInfo = getAppInfo(atPath: url)
|
||||
showAppInFiles(appInfo: appInfo!, mini: mini, appState: appState, locations: locations, showPopover: $showPopover)
|
||||
|
||||
// showPopover = false
|
||||
// updateOnMain {
|
||||
// appState.appInfo = .empty
|
||||
// if let storedAppInfo = appState.appInfoStore.first(where: { $0.path == appInfo?.path }) {
|
||||
// appState.appInfo = storedAppInfo
|
||||
//// appState.paths = storedAppInfo.fileSize.keys.map { $0 }//storedAppInfo.files
|
||||
// appState.selectedItems = Set(storedAppInfo.files)
|
||||
// withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
// if self.mini {
|
||||
// self.showPopover.toggle()
|
||||
// } else {
|
||||
// appState.currentView = .files
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // Handle the case where the appInfo is not found in the store
|
||||
// printOS("AppInfo not found in the cached store, searching again")
|
||||
// appState.appInfo = .empty
|
||||
// appState.appInfo = appInfo!
|
||||
// findPathsForApp(appInfo: appInfo!, appState: appState, locations: locations)
|
||||
// withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
// if self.mini {
|
||||
// self.showPopover.toggle()
|
||||
// } else {
|
||||
// appState.currentView = .files
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// updateOnMain {
|
||||
// appState.appInfo = appInfo!
|
||||
// findPathsForApp(appState: appState, locations: locations)
|
||||
// if self.mini {
|
||||
// self.showPopover = true
|
||||
// } else {
|
||||
// appState.currentView = .files
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Features.swift
|
||||
// Pearcleaner
|
||||
//
|
||||
// Created by Alin Lupascu on 3/1/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
func getFeatures(appState: AppState, show: Binding<Bool>, features: Binding<String>) {
|
||||
|
||||
let url = URL(string: "https://api.github.com/repos/alienator88/Pearcleaner/contents/features.json")!
|
||||
var request = URLRequest(url: url)
|
||||
request.setValue("application/vnd.github.VERSION.raw", forHTTPHeaderField: "Accept")
|
||||
request.setValue("2022-11-28", forHTTPHeaderField: "X-GitHub-Api-Version")
|
||||
|
||||
URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
if let data = data {
|
||||
do {
|
||||
let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
|
||||
if let jsonDict = jsonObject as? [String: String],
|
||||
let bundleVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
|
||||
let featureText = jsonDict[bundleVersion] {
|
||||
if features.wrappedValue != featureText.featureFormat() {
|
||||
updateOnMain {
|
||||
features.wrappedValue = featureText.featureFormat()
|
||||
show.wrappedValue = true
|
||||
}
|
||||
} else {
|
||||
show.wrappedValue = false
|
||||
// print("Same version")
|
||||
}
|
||||
|
||||
} else {
|
||||
show.wrappedValue = false
|
||||
// print("No features for version found")
|
||||
}
|
||||
} catch {
|
||||
show.wrappedValue = false
|
||||
printOS("Error reading features JSON from GitHub: \(error.localizedDescription)")
|
||||
}
|
||||
} else {
|
||||
show.wrappedValue = false
|
||||
printOS("Error reading features JSON from GitHub: \(error?.localizedDescription ?? "Unknown error")")
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
//import AudioToolbox
|
||||
|
||||
|
||||
// Get list of apps and sort it
|
||||
func getSortedApps() -> (systemApps: [AppInfo], userApps: [AppInfo]) {
|
||||
@@ -417,7 +415,7 @@ func findPathsForApp(appInfo: AppInfo = .empty, appState: AppState, locations: L
|
||||
// Append group containers
|
||||
let groupContainers = getGroupContainers(bundleURL: appState.appInfo.path)
|
||||
collection.append(contentsOf: groupContainers)
|
||||
let sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString })
|
||||
var sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString })
|
||||
|
||||
|
||||
// Calculate file details (sizes and icons)
|
||||
@@ -435,6 +433,11 @@ func findPathsForApp(appInfo: AppInfo = .empty, appState: AppState, locations: L
|
||||
fileIcon[path] = icon
|
||||
}
|
||||
|
||||
if sortedCollection.count == 1 {
|
||||
if let firstURL = sortedCollection.first, firstURL.path.contains(".Trash") {
|
||||
sortedCollection = []
|
||||
}
|
||||
}
|
||||
// Save to appState
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
|
||||
@@ -457,39 +460,61 @@ func findPathsForApp(appInfo: AppInfo = .empty, appState: AppState, locations: L
|
||||
|
||||
|
||||
// Load app paths on launch
|
||||
func loadAllPaths(allApps: [AppInfo], appState: AppState, locations: Locations) {
|
||||
func loadAllPaths(allApps: [AppInfo], appState: AppState, locations: Locations, reverseAddon: Bool = false, completion: @escaping () -> Void = {}) {
|
||||
|
||||
let dispatchGroup = DispatchGroup()
|
||||
let retryLimit = 120
|
||||
var currentRetryCount = 0
|
||||
|
||||
func checkCompletion() {
|
||||
if appState.appInfoStore.count == allApps.count {
|
||||
if reverseAddon {
|
||||
reversePathsSearch(appState: appState, locations: locations)
|
||||
}
|
||||
completion()
|
||||
} else {
|
||||
if currentRetryCount < retryLimit {
|
||||
currentRetryCount += 1
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
checkCompletion()
|
||||
}
|
||||
} else {
|
||||
printOS("loadAllPaths - Retry limit timed out. Unable to load all paths within 1 minute.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatchGroup.enter()
|
||||
|
||||
updateOnMain {
|
||||
appState.appInfoStore.removeAll()
|
||||
}
|
||||
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
checkCompletion()
|
||||
}
|
||||
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
for app in allApps {
|
||||
findPathsForApp(appInfo: app, appState: appState, locations: locations, backgroundRun: true) {
|
||||
findPathsForApp(appInfo: app, appState: appState, locations: locations, backgroundRun: true)
|
||||
}
|
||||
dispatchGroup.leave()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Load item in Files view
|
||||
func showAppInFiles(appInfo: AppInfo, mini: Bool, appState: AppState, locations: Locations, showPopover: Binding<Bool>) {
|
||||
showPopover.wrappedValue = false
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.0) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
updateOnMain {
|
||||
appState.appInfo = .empty
|
||||
appState.selectedItems = []
|
||||
if let storedAppInfo = appState.appInfoStore.first(where: { $0.path == appInfo.path }) {
|
||||
appState.appInfo = storedAppInfo
|
||||
appState.selectedItems = Set(storedAppInfo.files)
|
||||
withAnimation(Animation.easeIn(duration: 0.3)) {
|
||||
if mini {
|
||||
appState.currentView = .files
|
||||
showPopover.wrappedValue.toggle()
|
||||
} else {
|
||||
appState.currentView = .files
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateOnMain {
|
||||
appState.showProgress = true
|
||||
}
|
||||
// Handle the case where the appInfo is not found in the store
|
||||
withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
if mini {
|
||||
appState.currentView = .files
|
||||
@@ -498,17 +523,25 @@ func showAppInFiles(appInfo: AppInfo, mini: Bool, appState: AppState, locations:
|
||||
appState.currentView = .files
|
||||
}
|
||||
}
|
||||
printOS("AppInfo not found in the cached store, searching again")
|
||||
appState.appInfo = .empty
|
||||
} else {
|
||||
// Handle the case where the appInfo is not found in the store
|
||||
withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
appState.showProgress = true
|
||||
if mini {
|
||||
appState.currentView = .files
|
||||
showPopover.wrappedValue.toggle()
|
||||
} else {
|
||||
appState.currentView = .files
|
||||
}
|
||||
}
|
||||
appState.appInfo = appInfo
|
||||
findPathsForApp(appInfo: appInfo, appState: appState, locations: locations) {
|
||||
withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
updateOnMain {
|
||||
appState.selectedItems = Set(appInfo.files)
|
||||
appState.showProgress = false
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,6 +595,7 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
|
||||
let allNames = appState.appInfoStore.map { $0.appName.pearFormat() }
|
||||
let skipped = ["apple", "comapple", "temporary", "btserver", "proapps", "scripteditor", "ilife", "livefsd", "siritoday", "addressbook", "animoji", "appstore", "askpermission", "callhistory", "clouddocs", "diskimages", "dock", "facetime", "fileprovider", "instruments", "knowledge", "mobilesync", "syncservices", "homeenergyd", "icloud", "icdd", "networkserviceproxy", "familycircle", "geoservices", "installation", "passkit", "sharedimagecache", "desktop", "mbuseragent", "swiftpm", "baseband", "coresimulator", "photoslegacyupgrade", "photosupgrade", "siritts", "ipod", "globalpreferences", "apmanalytics", "apmexperiment", "avatarcache", "byhost", "contextstoreagent", "mobilemeaccounts", "intentbuilderc", "loginwindow", "momc", "replayd", "sharedfilelistd", "clang", "audiocomponent", "csexattrcryptoservice", "livetranscriptionagent", "sandobxhelper", "statuskitagent", "betaenrollmentd", "contentlinkingd", "diagnosticextensionsd", "gamed", "heard", "homed", "itunescloudd", "lldb", "mds", "mediaanalysisd", "metrickitd", "mobiletimerd", "proactived", "ptpcamerad", "studentd", "talagent", "watchlistd", "apptranslocation", "xcrun", "ds_store", "caches", "crashreporter"] // Skip system folders
|
||||
|
||||
|
||||
// Skip locations that might not exist
|
||||
for location in locations.reverse.paths {
|
||||
if !fileManager.fileExists(atPath: location) {
|
||||
@@ -600,8 +634,6 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
|
||||
|
||||
}
|
||||
|
||||
// let sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString })
|
||||
|
||||
// Calculate file details (sizes and icons)
|
||||
var fileSize: [URL: Int64] = [:]
|
||||
var fileIcon: [URL: NSImage?] = [:]
|
||||
@@ -622,7 +654,7 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
|
||||
updateOnMain {
|
||||
updatedZombieFile.fileSize = fileSize
|
||||
updatedZombieFile.fileIcon = fileIcon
|
||||
// appState.selectedZombieItems = Set(sortedCollection)
|
||||
// appState.selectedZombieItems = Set(sortedCollection)
|
||||
appState.zombieFile = updatedZombieFile
|
||||
appState.showProgress = false
|
||||
}
|
||||
@@ -640,10 +672,6 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
|
||||
// Move files to trash using applescript/Finder so it asks for user password if needed
|
||||
func moveFilesToTrash(at fileURLs: [URL], completion: @escaping () -> Void = {}) {
|
||||
@AppStorage("settings.sentinel.enable") var sentinel: Bool = false
|
||||
if sentinel {
|
||||
launchctl(load: false)
|
||||
}
|
||||
|
||||
var filesFinder = fileURLs
|
||||
var filesSudo: [URL] = []
|
||||
|
||||
@@ -689,107 +717,6 @@ func moveFilesToTrash(at fileURLs: [URL], completion: @escaping () -> Void = {})
|
||||
}
|
||||
}
|
||||
|
||||
//func moveFilesToTrash(at fileURLs: [URL] = [], appState: AppState, undo: Bool = false, completion: @escaping () -> Void = {}) {
|
||||
// @AppStorage("settings.sentinel.enable") var sentinel: Bool = false
|
||||
// if sentinel {
|
||||
// launchctl(load: false)
|
||||
// }
|
||||
//
|
||||
// let home = FileManager.default.homeDirectoryForCurrentUser.path
|
||||
//
|
||||
// if undo {
|
||||
// for url in appState.trashedFiles {
|
||||
// let file = url.lastPathComponent
|
||||
// let destinationURL = url.deletingLastPathComponent()
|
||||
//
|
||||
// let destinationPath = destinationURL.path
|
||||
// let trashPath = "\(home)/.Trash/\(file)"
|
||||
//
|
||||
// if !destinationPath.starts(with: home) {
|
||||
// executePrivilegedCommand(launchPath: "/bin/cp", arguments: ["-R"] + [trashPath, destinationPath])
|
||||
// } else {
|
||||
// let task = Process()
|
||||
// task.launchPath = "/bin/cp"
|
||||
// task.arguments = ["-R"] + [trashPath, destinationPath]
|
||||
//
|
||||
// let pipe = Pipe()
|
||||
// task.standardOutput = pipe
|
||||
// task.launch()
|
||||
//
|
||||
// task.waitUntilExit()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// AudioServicesPlaySystemSound(0xf);
|
||||
//
|
||||
// updateOnMain {
|
||||
// appState.trashedFiles.removeAll()
|
||||
// }
|
||||
//
|
||||
// } else {
|
||||
// let privilegedURLs = fileURLs.filter { !$0.path.starts(with: home) }
|
||||
//
|
||||
// if !privilegedURLs.isEmpty {
|
||||
// let filePaths = fileURLs.map { $0.path }
|
||||
// executePrivilegedCommand(launchPath: "/bin/mv", arguments: ["-f"] + filePaths + ["\(home)/.Trash"])
|
||||
// } else {
|
||||
// let filePaths = fileURLs.map { $0.path }
|
||||
// let task = Process()
|
||||
// task.launchPath = "/bin/mv"
|
||||
// task.arguments = ["-f"] + filePaths + ["\(home)/.Trash"]
|
||||
//
|
||||
// let pipe = Pipe()
|
||||
// task.standardOutput = pipe
|
||||
// task.launch()
|
||||
//
|
||||
// task.waitUntilExit()
|
||||
// }
|
||||
//
|
||||
// AudioServicesPlaySystemSound(0x10);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// completion()
|
||||
//}
|
||||
|
||||
// Audio
|
||||
//drag to trash.aif
|
||||
//AudioServicesPlaySystemSound(0x10);
|
||||
|
||||
//poof item of dock.aif
|
||||
//AudioServicesPlaySystemSound(0xf);
|
||||
|
||||
//func moveFilesToTrash(at fileURLs: [URL], completion: @escaping () -> Void = {}) {
|
||||
// @AppStorage("settings.sentinel.enable") var sentinel: Bool = false
|
||||
// if sentinel {
|
||||
// launchctl(load: false)
|
||||
// }
|
||||
//
|
||||
// let privilegedURLs = fileURLs.filter { !$0.path.starts(with: home) }
|
||||
//
|
||||
// if !privilegedURLs.isEmpty {
|
||||
// print("Found system files")
|
||||
// // Use privileged sudo mv function
|
||||
// let filePaths = privilegedURLs.map { $0.path }
|
||||
// executePrivilegedCommand(launchPath: "/bin/mv", arguments: filePaths + ["\(home)/.Trash"])
|
||||
// completion()
|
||||
// } else {
|
||||
// // Use regular shell process for files within the user's home directory
|
||||
// let filePaths = fileURLs.map { $0.path }
|
||||
// let task = Process()
|
||||
// task.launchPath = "/bin/mv"
|
||||
// task.arguments = filePaths + ["\(home)/.Trash"]
|
||||
//
|
||||
// let pipe = Pipe()
|
||||
// task.standardOutput = pipe
|
||||
// task.launch()
|
||||
//
|
||||
// task.waitUntilExit()
|
||||
//
|
||||
// completion()
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
func isSocketFile(at url: URL) -> Bool {
|
||||
do {
|
||||
@@ -804,8 +731,6 @@ func isSocketFile(at url: URL) -> Bool {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Undo trash action
|
||||
func undoTrash(appState: AppState, completion: @escaping () -> Void = {}) {
|
||||
let scriptSource = """
|
||||
@@ -844,55 +769,3 @@ func undoTrash(appState: AppState, completion: @escaping () -> Void = {}) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//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 {
|
||||
// printOS("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 {
|
||||
// printOS("Failed to run task: \(error)")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// completion()
|
||||
//}
|
||||
|
||||
@@ -1,599 +0,0 @@
|
||||
////
|
||||
//// 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)
|
||||
//// )
|
||||
////}
|
||||
@@ -70,6 +70,46 @@ struct NavButtonBottomBarStyle: ButtonStyle {
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct InfoButton: View {
|
||||
@State private var isPopoverPresented: Bool = false
|
||||
let text: String
|
||||
let color: Color?
|
||||
|
||||
var body: some View {
|
||||
Button(action: {
|
||||
self.isPopoverPresented.toggle()
|
||||
}) {
|
||||
Image(systemName: "info.circle.fill")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 14, height: 14)
|
||||
.foregroundColor(color?.opacity(0.7) ?? Color("mode").opacity(0.7))
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.onHover { isHovered in
|
||||
if isHovered {
|
||||
NSCursor.pointingHand.push()
|
||||
} else {
|
||||
NSCursor.pop()
|
||||
}
|
||||
}
|
||||
.popover(isPresented: $isPopoverPresented, arrowEdge: .bottom) {
|
||||
VStack {
|
||||
Spacer()
|
||||
Text(text)
|
||||
.font(.callout)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
Spacer()
|
||||
}
|
||||
.frame(width: 300)
|
||||
}
|
||||
.padding(.horizontal, 5)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct WarningPopoverView: View {
|
||||
var label: String
|
||||
var bodyText: String
|
||||
@@ -82,10 +122,14 @@ struct WarningPopoverView: View {
|
||||
.foregroundStyle(.red)
|
||||
.popover(isPresented: $isPresented, arrowEdge: .top) {
|
||||
VStack {
|
||||
Spacer()
|
||||
Text(bodyText)
|
||||
.font(.callout)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.font(.title2)
|
||||
Spacer()
|
||||
}
|
||||
.frame(width: 300)
|
||||
}
|
||||
|
||||
Text(label)
|
||||
@@ -100,6 +144,121 @@ struct WarningPopoverView: View {
|
||||
}
|
||||
|
||||
|
||||
public struct NewFeatureView: View {
|
||||
var text: String
|
||||
var mini: Bool
|
||||
@Binding var showFeature: Bool
|
||||
|
||||
public var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
Text("New features for v\((Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String)!)!")
|
||||
.font(.headline).bold()
|
||||
Spacer()
|
||||
Button("") {
|
||||
withAnimation(Animation.easeInOut(duration: 0.5)) {
|
||||
showFeature = false
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", help: "Close", color: .gray))
|
||||
.onHover { isHovered in
|
||||
if isHovered {
|
||||
NSCursor.pointingHand.push()
|
||||
} else {
|
||||
NSCursor.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
ScrollView() {
|
||||
Text(text)
|
||||
.font(.callout)
|
||||
.multilineTextAlignment(.leading)
|
||||
.padding(.trailing)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom)
|
||||
|
||||
}
|
||||
.frame(maxWidth: mini ? 200 : 400, maxHeight: mini ? 300 : 250)
|
||||
.background(.ultraThinMaterial)
|
||||
.cornerRadius(10)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.strokeBorder(Color("mode").opacity(0.2), lineWidth: 0.6)
|
||||
)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct SlideableDivider: View {
|
||||
@Binding var dimension: Double
|
||||
@State private var dimensionStart: Double?
|
||||
@State private var handleWidth: Double = 2
|
||||
@State private var handleHeight: Double = 30
|
||||
public init(dimension: Binding<Double>) {
|
||||
self._dimension = dimension
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
Rectangle()
|
||||
.foregroundStyle(Color.gray.opacity(0.3))
|
||||
.frame(width: 1)
|
||||
.overlay(
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
RoundedRectangle(cornerRadius: 50)
|
||||
.fill(Color("mode").opacity(0.3))
|
||||
.frame(width: handleWidth, height: handleHeight)
|
||||
.onHover { inside in
|
||||
if inside {
|
||||
NSCursor.resizeLeftRight.push()
|
||||
|
||||
} else {
|
||||
NSCursor.pop()
|
||||
|
||||
}
|
||||
}
|
||||
.contextMenu {
|
||||
Button("Reset Size") {
|
||||
dimension = 280
|
||||
}
|
||||
}
|
||||
.gesture(drag)
|
||||
Spacer()
|
||||
}
|
||||
.offset(x: 5)
|
||||
)
|
||||
}
|
||||
|
||||
var drag: some Gesture {
|
||||
DragGesture(minimumDistance: 5, coordinateSpace: CoordinateSpace.global)
|
||||
.onChanged { val in
|
||||
if dimensionStart == nil {
|
||||
dimensionStart = dimension
|
||||
}
|
||||
let delta = val.location.x - val.startLocation.x
|
||||
let newDimension = dimensionStart! + Double(delta)
|
||||
|
||||
// Set minimum and maximum width
|
||||
let minWidth: Double = 250
|
||||
let maxWidth: Double = 350
|
||||
dimension = max(minWidth, min(maxWidth, newDimension))
|
||||
NSCursor.closedHand.set()
|
||||
handleWidth = 4
|
||||
handleHeight = 40
|
||||
}
|
||||
.onEnded { val in
|
||||
dimensionStart = nil
|
||||
NSCursor.arrow.set()
|
||||
handleWidth = 2
|
||||
handleHeight = 30
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct LabeledDivider: View {
|
||||
let label: String
|
||||
@@ -140,7 +299,6 @@ struct AnimatedSearchStyle: TextFieldStyle {
|
||||
if isHovered || !text.isEmpty {
|
||||
|
||||
configuration
|
||||
// .frame(minWidth: 130)
|
||||
.frame(height: 15)
|
||||
.font(.title3)
|
||||
.textFieldStyle(PlainTextFieldStyle())
|
||||
@@ -242,30 +400,9 @@ struct SimpleSearchStyle: TextFieldStyle {
|
||||
}
|
||||
|
||||
configuration
|
||||
// .frame(minWidth: mini ? 80 : 300)
|
||||
// .frame(maxWidth: mini ? 150 : 300)
|
||||
.font(.title3)
|
||||
.textFieldStyle(PlainTextFieldStyle())
|
||||
|
||||
// Image(systemName: "arrow.triangle.2.circlepath")
|
||||
// .resizable()
|
||||
// .aspectRatio(contentMode: .fit)
|
||||
// .frame(width: 15, height: 15)
|
||||
// .padding(.trailing, 5)
|
||||
// .foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5))
|
||||
// .onTapGesture {
|
||||
// withAnimation {
|
||||
// // Refresh Apps list
|
||||
// appState.reload.toggle()
|
||||
// let sortedApps = getSortedApps()
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
// appState.sortedApps.userApps = sortedApps.userApps
|
||||
// appState.sortedApps.systemApps = sortedApps.systemApps
|
||||
// appState.reload.toggle()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
if trash && text != "" {
|
||||
Image(systemName: "xmark")
|
||||
@@ -472,42 +609,6 @@ private let redBG: AnyShapeStyle = AnyShapeStyle(
|
||||
|
||||
|
||||
|
||||
// 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
|
||||
@@ -526,12 +627,6 @@ struct PillPicker: View {
|
||||
.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))
|
||||
@@ -561,7 +656,6 @@ struct PillPicker: View {
|
||||
.offset(y: 1)
|
||||
)
|
||||
)
|
||||
// .background(Color.black.opacity(0.06))
|
||||
.clipShape(Capsule())
|
||||
}
|
||||
}
|
||||
@@ -574,11 +668,11 @@ struct PearDropView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .center, spacing: 0) {
|
||||
HStack(spacing: 0) {
|
||||
LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||
.frame(width: 195)
|
||||
LinearGradient(gradient: Gradient(colors: [.orange, .gray]), startPoint: .leading, endPoint: .trailing)
|
||||
LinearGradient(gradient: Gradient(colors: [.orange, Color("mode").opacity(0.5)]), startPoint: .leading, endPoint: .trailing)
|
||||
.frame(width: 10)
|
||||
LinearGradient(gradient: Gradient(colors: [.gray, .gray]), startPoint: .leading, endPoint: .trailing)
|
||||
LinearGradient(gradient: Gradient(colors: [Color("mode").opacity(0.5), Color("mode").opacity(0.5)]), startPoint: .leading, endPoint: .trailing)
|
||||
.frame(width: 300)
|
||||
}
|
||||
.mask(
|
||||
@@ -588,90 +682,10 @@ struct PearDropView: View {
|
||||
.frame(width: 500, height: 120)
|
||||
.padding()
|
||||
)
|
||||
// LinearGradient(gradient: Gradient(colors: [.gray, .gray]), startPoint: .leading, endPoint: .trailing)
|
||||
// .mask(
|
||||
// Image("logo_text_small")
|
||||
// .resizable()
|
||||
// .scaledToFit()
|
||||
// .frame(minWidth: 300, maxWidth: 350)
|
||||
// .frame(height: 100)
|
||||
// .padding()
|
||||
// )
|
||||
|
||||
// LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||
// .mask(
|
||||
// Image(systemName: "plus.square.dashed")
|
||||
// .resizable()
|
||||
// .scaledToFit()
|
||||
// .frame(width: 50, height: 50)
|
||||
// .padding()
|
||||
// )
|
||||
}
|
||||
.frame(height: 120)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// .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)
|
||||
|
||||
@@ -53,7 +53,6 @@ func checkFullDiskAccessForApp() -> Bool {
|
||||
process.standardError = pipeErr
|
||||
process.launch()
|
||||
|
||||
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
let dataErr = pipeErr.fileHandleForReading.readDataToEndOfFile()
|
||||
|
||||
let output = String(data: dataErr, encoding: .utf8)
|
||||
@@ -86,7 +85,6 @@ func checkAndRequestFullDiskAccess(appState: AppState, skipAlert: Bool = false)
|
||||
process.standardError = pipeErr
|
||||
process.launch()
|
||||
|
||||
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
let dataErr = pipeErr.fileHandleForReading.readDataToEndOfFile()
|
||||
|
||||
let output = String(data: dataErr, encoding: .utf8)
|
||||
@@ -100,32 +98,11 @@ func checkAndRequestFullDiskAccess(appState: AppState, skipAlert: Bool = false)
|
||||
diskP = false
|
||||
if !skipAlert {
|
||||
NewWin.show(appState: appState, width: 500, height: 350, newWin: .perm)
|
||||
// appState.alertType = .diskAccess
|
||||
// appState.showAlert = true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// let fileURL = URL(fileURLWithPath: "/Library/Application Support/com.apple.TCC/TCC.db")
|
||||
//
|
||||
// let accessStatus = FileManager.default.isReadableFile(atPath: fileURL.path)
|
||||
// printOS(accessStatus)
|
||||
// if accessStatus {
|
||||
// diskP = true
|
||||
// _ = checkAndRequestAccessibilityAccess(appState: appState)
|
||||
//
|
||||
// return true
|
||||
// } else {
|
||||
// diskP = false
|
||||
// if !skipAlert {
|
||||
// appState.alertType = .diskAccess
|
||||
// appState.showAlert = true
|
||||
// }
|
||||
//
|
||||
// return false
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +237,13 @@ extension String {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Extend string to replace - and | with custom characters
|
||||
extension String {
|
||||
func featureFormat() -> String {
|
||||
return self.replacingOccurrences(of: "- ", with: "• ").replacingOccurrences(of: "|", with: "\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Trash Relationship ---
|
||||
extension FileManager {
|
||||
@@ -279,21 +263,6 @@ func printOS(_ items: Any..., separator: String = " ", terminator: String = "\n"
|
||||
}
|
||||
|
||||
|
||||
// --- 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]) -> Int64 {
|
||||
@@ -354,7 +323,6 @@ extension Array where Element == URL {
|
||||
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" {
|
||||
@@ -370,7 +338,6 @@ extension Array where Element == URL {
|
||||
} else {
|
||||
totalSize += resourceValues.totalFileAllocatedSize ?? 0
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -396,7 +363,6 @@ func presentAlert(appState: AppState) -> Alert {
|
||||
case .update:
|
||||
return Alert(title: Text("Update Available 🥳"), message: Text("You may choose to install the update now, otherwise you may check again later from Settings"), primaryButton: .default(Text("Install")) {
|
||||
downloadUpdate(appState: appState)
|
||||
// launchUpdate()
|
||||
appState.alertType = .off
|
||||
}, secondaryButton: .cancel())
|
||||
case .no_update:
|
||||
@@ -525,10 +491,6 @@ func launchctl(load: Bool) {
|
||||
|
||||
task.launch()
|
||||
|
||||
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
// if let output = String(data: data, encoding: .utf8) {
|
||||
// printOS("Output: \(output)")
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,40 +505,5 @@ func getCurrentTimestamp() -> String {
|
||||
}
|
||||
|
||||
|
||||
// Execute sudo command
|
||||
//func executePrivilegedCommand(launchPath: String, arguments: [String]) {
|
||||
// let task = Process()
|
||||
// task.launchPath = launchPath
|
||||
// task.arguments = arguments
|
||||
//
|
||||
// var authorization: AuthorizationRef? = nil
|
||||
// let status = AuthorizationCreate(nil, nil, AuthorizationFlags(), &authorization)
|
||||
//
|
||||
// if status == errAuthorizationSuccess {
|
||||
// if let rightName = (kAuthorizationRightExecute as NSString).utf8String {
|
||||
// let item = AuthorizationItem(name: rightName, valueLength: 0, value: nil, flags: 0)
|
||||
// var items = [item]
|
||||
// items.withUnsafeMutableBufferPointer { bufferPointer in
|
||||
// var rights = AuthorizationRights(count: UInt32(bufferPointer.count), items: bufferPointer.baseAddress)
|
||||
//
|
||||
// let status = AuthorizationCopyRights(authorization!, &rights, nil, AuthorizationFlags([.extendRights, .interactionAllowed]), nil)
|
||||
//
|
||||
// if status == errAuthorizationSuccess {
|
||||
// task.launch()
|
||||
// } else {
|
||||
// printOS("Authorization failed.")
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// printOS("Failed to convert rightName to C-string.")
|
||||
// }
|
||||
// } else {
|
||||
// printOS("Authorization creation failed.")
|
||||
// }
|
||||
//}
|
||||
|
||||
// executePrivilegedCommand(launchPath: "/bin/mv", arguments: ["-f"] + filesSudoPaths + ["\(home)/.Trash"])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,11 @@ struct PearcleanerApp: App {
|
||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||
@AppStorage("settings.general.miniview") private var miniView: Bool = true
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@AppStorage("settings.general.features") private var features: String = ""
|
||||
@State private var search = ""
|
||||
@State private var showPopover: Bool = false
|
||||
@State private var showFeature: Bool = false
|
||||
|
||||
var body: some Scene {
|
||||
|
||||
@@ -30,7 +33,7 @@ struct PearcleanerApp: App {
|
||||
|
||||
WindowGroup {
|
||||
Group {
|
||||
|
||||
ZStack() {
|
||||
if !mini {
|
||||
AppListView(search: $search, showPopover: $showPopover)
|
||||
.environmentObject(locations)
|
||||
@@ -39,6 +42,14 @@ struct PearcleanerApp: App {
|
||||
.environmentObject(locations)
|
||||
}
|
||||
|
||||
if showFeature {
|
||||
NewFeatureView(text: features, mini: mini, showFeature: $showFeature)
|
||||
.transition(.opacity)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.environmentObject(appState)
|
||||
.preferredColorScheme(displayMode.colorScheme)
|
||||
@@ -86,18 +97,21 @@ struct PearcleanerApp: App {
|
||||
appState.sortedApps.systemApps = sortedApps.systemApps
|
||||
|
||||
|
||||
// Find all app paths on load
|
||||
if instantSearch {
|
||||
loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations)
|
||||
}
|
||||
|
||||
getFeatures(appState: appState, show: $showFeature, features: $features)
|
||||
|
||||
#if !DEBUG
|
||||
Task {
|
||||
|
||||
// Find all app paths on load
|
||||
loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations)
|
||||
|
||||
// Make sure App Support folder exists in the future if needed for storage
|
||||
ensureApplicationSupportFolderExists(appState: appState)
|
||||
|
||||
// Check for updates 1 minute after app launch
|
||||
// Check for updates after app launch
|
||||
if diskP {
|
||||
loadGithubReleases(appState: appState)
|
||||
}
|
||||
@@ -111,7 +125,7 @@ struct PearcleanerApp: App {
|
||||
|
||||
// TIMERS ////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Check for app updates every 8 hours or whatever user saved setting. Also refresh autosuggestion list
|
||||
// Check for app updates every 8 hours or whatever user saved setting.
|
||||
let updateSeconds = updateTimeframe.daysToSeconds
|
||||
_ = Timer.scheduledTimer(withTimeInterval: updateSeconds, repeats: true) { _ in
|
||||
DispatchQueue.main.async {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_16x16@2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "16x16"
|
||||
@@ -19,7 +18,6 @@
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_32x32@2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "32x32"
|
||||
@@ -31,7 +29,6 @@
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_128x128@2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "128x128"
|
||||
@@ -43,7 +40,6 @@
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_256x256@2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "256x256"
|
||||
@@ -55,7 +51,6 @@
|
||||
"size" : "512x512"
|
||||
},
|
||||
{
|
||||
"filename" : "icon_512x512@2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "512x512"
|
||||
|
||||
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 513 KiB |
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "logo_combo_small.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x50",
|
||||
"green" : "0xC3",
|
||||
"red" : "0x79"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x50",
|
||||
"green" : "0xC3",
|
||||
"red" : "0x79"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "pear_small.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 11 KiB |
@@ -36,10 +36,11 @@ struct AboutSettingsTab: View {
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
HStack() {
|
||||
Text("Credits and Inspiration").font(.title2)
|
||||
Text("Credits").font(.title2)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.leading)
|
||||
.padding(.bottom)
|
||||
|
||||
HStack{
|
||||
Image(systemName: "paintbrush.pointed")
|
||||
|
||||
@@ -19,9 +19,10 @@ struct GeneralSettingsTab: View {
|
||||
@AppStorage("settings.general.sidebarWidth") private var sidebarWidth: Double = 280
|
||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
|
||||
@State private var diskStatus: Bool = false
|
||||
@State private var accessStatus: Bool = false
|
||||
@State private var selectedTheme = "Auto"
|
||||
private let themes = ["Auto", "Dark", "Light"]
|
||||
@Binding var showPopover: Bool
|
||||
|
||||
@@ -57,25 +58,24 @@ struct GeneralSettingsTab: View {
|
||||
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Image(systemName: "sidebar.left")
|
||||
Image(systemName: instantSearch ? "bolt" : "bolt.slash")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
Text("Adjust sidebar width")
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(instantSearch ? "Instant search is enabled" : "Instant search is disabled")")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
InfoButton(text: "When instant search is enabled, all application files are gathered and cached for later use on startup instead of on each app click. There might be a slight delay of a few seconds when launching Pearcleaner depending on the amount of apps you have installed.", color: nil)
|
||||
|
||||
Spacer()
|
||||
Slider(value: $sidebarWidth, in: 200...360) {
|
||||
// Text("\(Int(sidebarWidth))")
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.frame(width: 185)
|
||||
Button("") {
|
||||
sidebarWidth = 280
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.uturn.left.circle", help: "Reset to default size", color: Color("mode")))
|
||||
Toggle(isOn: $instantSearch, label: {
|
||||
})
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
.padding(5)
|
||||
.padding(.leading)
|
||||
@@ -89,7 +89,7 @@ struct GeneralSettingsTab: View {
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("Set color mode")
|
||||
Text("Set application color mode")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
@@ -143,7 +143,7 @@ struct GeneralSettingsTab: View {
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(mini ? "Mini window mode" : "Full size window mode")")
|
||||
Text("\(mini ? "Mini window mode selected" : "Full size window mode selected")")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
@@ -182,6 +182,9 @@ struct GeneralSettingsTab: View {
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
InfoButton(text: "In mini window mode, you can have Pearcleaner startup to the Apps List view or the Drop Target view.", color: nil)
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $miniView, label: {
|
||||
})
|
||||
@@ -202,10 +205,13 @@ struct GeneralSettingsTab: View {
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(popoverStay ? "Popover window doesn't hide on outside click" : "Popover window hides on outside click")")
|
||||
Text("\(popoverStay ? "Popover window will stay on top" : "Popover window will not stay on top")")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
InfoButton(text: "In mini window mode, if you pin the Files popover on top, clicking away from the window will not dismiss it. Otherwise, it will dismiss by clicking anywhere outside the popover.", color: nil)
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $popoverStay, label: {
|
||||
})
|
||||
@@ -330,6 +336,11 @@ struct GeneralSettingsTab: View {
|
||||
.onAppear {
|
||||
diskStatus = checkAndRequestFullDiskAccess(appState: appState, skipAlert: true)
|
||||
accessStatus = checkAndRequestAccessibilityAccess(appState: appState)
|
||||
// if displayMode.colorScheme == .dark {
|
||||
// selectedTheme = "Dark"
|
||||
// } else if displayMode.colorScheme == .light {
|
||||
// selectedTheme = "Light"
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
//
|
||||
// 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: 0) {
|
||||
Image(systemName: diskStatus ? "externaldrive" : "externaldrive")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(diskStatus ? .green : .red)
|
||||
Text(diskStatus ? "Full Disk permission granted" : "Full Disk permission not granted")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
Spacer()
|
||||
|
||||
Button("") {
|
||||
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") {
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "gear", help: "View disk permissions pane", color: Color("mode")))
|
||||
|
||||
}
|
||||
.padding(5)
|
||||
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Image(systemName: accessStatus ? "accessibility" : "accessibility")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(accessStatus ? .green : .red)
|
||||
Text(accessStatus ? "Accessibility permission granted" : "Accessibility permission not granted")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
Spacer()
|
||||
|
||||
Button("") {
|
||||
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") {
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "gear", help: "View accessibility permissions pane", color: Color("mode")))
|
||||
|
||||
}
|
||||
.padding(5)
|
||||
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// 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(SentinelToggleStyle())
|
||||
.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))
|
||||
)
|
||||
Text("If you uninstall Pearcleaner, make sure to disable Sentinel first").font(.footnote)
|
||||
.foregroundStyle(Color.red)
|
||||
.padding()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
.padding(20)
|
||||
.frame(width: 450, height: 130)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,18 +20,6 @@ struct SettingsView: View {
|
||||
}
|
||||
.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: "cloud")
|
||||
@@ -56,3 +44,5 @@ struct SettingsView: View {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -71,24 +71,26 @@ struct UpdateSettingsTab: View {
|
||||
|
||||
HStack(alignment: .center, spacing: 20) {
|
||||
Spacer()
|
||||
|
||||
Button("Update Notes"){
|
||||
loadGithubReleases(appState: appState)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "list.bullet", help: "Check release notes", color: Color("mode")))
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Force Update"){
|
||||
loadGithubReleases(appState: appState, manual: true)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.down.square", help: "Check for updates", color: Color("mode")))
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("GitHub"){
|
||||
NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner/releases")!)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "link", help: "View releases on GitHub", color: Color("mode")))
|
||||
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
@@ -130,13 +132,9 @@ func checkForUpdate(appState: AppState, manual: Bool = false) {
|
||||
let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
|
||||
if latestRelease.tag_name > currentVersion ?? "" {
|
||||
NewWin.show(appState: appState, width: 500, height: 440, newWin: .update)
|
||||
// appState.alertType = .update
|
||||
// appState.showAlert = true
|
||||
} else {
|
||||
if manual {
|
||||
NewWin.show(appState: appState, width: 500, height: 300, newWin: .no_update)
|
||||
// appState.alertType = .no_update
|
||||
// appState.showAlert = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,22 +213,14 @@ func UnzipAndReplace(DownloadedFileURL fileURL: String, appState: AppState) {
|
||||
|
||||
// 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]
|
||||
process.executableURL = URL(fileURLWithPath: "/usr/bin/ditto")
|
||||
process.arguments = ["-xk", fileURL, appDirectory]
|
||||
// let pipe = Pipe()
|
||||
process.standardOutput = FileHandle.nullDevice
|
||||
process.standardError = FileHandle.nullDevice
|
||||
|
||||
try process.run()
|
||||
process.waitUntilExit()
|
||||
|
||||
// let outputData = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
// let output = String(decoding: outputData, as: UTF8.self)
|
||||
//
|
||||
// writeLog(string: output)
|
||||
|
||||
updateOnMain {
|
||||
appState.progressBar.0 = "Deleting update file"
|
||||
appState.progressBar.1 = 0.8
|
||||
@@ -239,12 +229,6 @@ func UnzipAndReplace(DownloadedFileURL fileURL: String, appState: AppState) {
|
||||
// After unzipping, remove the update file
|
||||
try fileManager.removeItem(atPath: fileURL)
|
||||
|
||||
// Show Restart dialog
|
||||
// updateOnMain {
|
||||
// appState.alertType = .restartApp
|
||||
// appState.showAlert = true
|
||||
// }
|
||||
|
||||
|
||||
} catch {
|
||||
printOS("Error updating the app: \(error)")
|
||||
|
||||
@@ -26,8 +26,18 @@ struct AppListItems: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
|
||||
|
||||
|
||||
HStack(alignment: .center) {
|
||||
|
||||
if isHovered || isSelected {
|
||||
RoundedRectangle(cornerRadius: 50)
|
||||
.fill(isSelected ? Color("pear") : Color("mode").opacity(0.5))
|
||||
.frame(width: isSelected ? 4 : 2, height: 25)
|
||||
.padding(.trailing, 5)
|
||||
}
|
||||
|
||||
if let appIcon = appInfo.appIcon {
|
||||
Image(nsImage: appIcon)
|
||||
.resizable()
|
||||
@@ -35,6 +45,7 @@ struct AppListItems: View {
|
||||
.frame(width: 30, height: 30)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text(appInfo.appName)
|
||||
.font(.system(size: 12))
|
||||
@@ -56,8 +67,6 @@ struct AppListItems: View {
|
||||
.background(
|
||||
Capsule().strokeBorder(Color("mode").opacity(0.3), lineWidth: 1)
|
||||
)
|
||||
// .background(Color("mode").opacity(0.1))
|
||||
// .clipShape(.capsule)
|
||||
}
|
||||
if appInfo.wrapped {
|
||||
Text("iOS")
|
||||
@@ -68,22 +77,12 @@ struct AppListItems: View {
|
||||
.background(
|
||||
Capsule().strokeBorder(Color("mode").opacity(0.3), lineWidth: 1)
|
||||
)
|
||||
// .background(Color("mode").opacity(0.1))
|
||||
// .clipShape(.capsule)
|
||||
}
|
||||
|
||||
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: 30)
|
||||
.padding(.leading, 5)
|
||||
.offset(x: 20)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -97,25 +96,5 @@ struct AppListItems: View {
|
||||
.onTapGesture {
|
||||
showAppInFiles(appInfo: appInfo, mini: mini, appState: appState, locations: locations, showPopover: $showPopover)
|
||||
}
|
||||
|
||||
// .popover(isPresented: Binding(
|
||||
// get: { showPopover && appState.appInfo.id == appInfo.id},
|
||||
// set: { _ in showPopover = false}
|
||||
// ), attachmentAnchor: .rect(.rect(CGRect(x: windowSettings.loadWindowSettings().width - 17, y: 15, width: 0, height: 0))), arrowEdge: .trailing) {
|
||||
|
||||
// .popover(isPresented: $showPopover, arrowEdge: .trailing) {
|
||||
// VStack {
|
||||
// FilesView(showPopover: $showPopover, search: $search)
|
||||
// .id(appState.appInfo.id)
|
||||
// }
|
||||
// .interactiveDismissDisabled(popoverStay)
|
||||
// .background(
|
||||
// Rectangle()
|
||||
// .fill(Color("pop"))
|
||||
// .padding(-80)
|
||||
// )
|
||||
// .frame(minWidth: 650, minHeight: 500)
|
||||
//
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ struct AppListView: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@AppStorage("settings.general.glass") private var glass: Bool = false
|
||||
@AppStorage("settings.general.sidebarWidth") private var sidebarWidth: Double = 280
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@Binding var search: String
|
||||
@State private var showSys: Bool = true
|
||||
@State private var showUsr: Bool = true
|
||||
// @State private var sidebar: Bool = true
|
||||
@Binding var showPopover: Bool
|
||||
|
||||
var filteredUserApps: [AppInfo] {
|
||||
@@ -38,14 +38,18 @@ struct AppListView: View {
|
||||
|
||||
HStack(alignment: .center, spacing: 0) {
|
||||
// App List
|
||||
if appState.sidebar {
|
||||
ZStack {
|
||||
HStack(spacing: 0){
|
||||
|
||||
if appState.reload {
|
||||
VStack {
|
||||
Spacer()
|
||||
ProgressView("Loading apps and files")
|
||||
ProgressView(instantSearch ? "Refreshing app list and caching files" : "Refreshing app list")
|
||||
if instantSearch {
|
||||
Image(systemName: "bolt")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 30, height: 30)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.frame(width: sidebarWidth)
|
||||
@@ -75,7 +79,6 @@ struct AppListView: View {
|
||||
Divider().padding(.horizontal, 5)
|
||||
}
|
||||
}
|
||||
// .padding(.bottom)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -104,14 +107,11 @@ struct AppListView: View {
|
||||
}
|
||||
|
||||
|
||||
Divider().foregroundStyle(.red)
|
||||
}
|
||||
}
|
||||
.background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil)
|
||||
.transition(.move(edge: .leading))
|
||||
|
||||
Spacer()
|
||||
}
|
||||
SlideableDivider(dimension: $sidebarWidth)
|
||||
|
||||
|
||||
// Details View
|
||||
@@ -130,12 +130,19 @@ struct AppListView: View {
|
||||
}
|
||||
}
|
||||
.transition(.move(edge: .leading))
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(minWidth: 900, minHeight: 600)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
|
||||
// MARK: Background for whole app
|
||||
// .background{
|
||||
// Image("peakpx")
|
||||
// .resizable()
|
||||
// .scaledToFill()
|
||||
// .edgesIgnoringSafeArea(.all)
|
||||
// GlassEffect(material: .sidebar, blendingMode: .withinWindow)
|
||||
// .edgesIgnoringSafeArea(.all)
|
||||
// }
|
||||
// .background(Color("bg").opacity(1))
|
||||
// .background(VisualEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all))
|
||||
}
|
||||
@@ -191,12 +198,12 @@ struct Header: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@EnvironmentObject var locations: Locations
|
||||
@Binding var showPopover: Bool
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(title).opacity(0.5)
|
||||
|
||||
// Spacer()
|
||||
Text(title).foregroundStyle(Color("mode")).opacity(0.5)
|
||||
|
||||
HStack {
|
||||
if hovered {
|
||||
@@ -214,8 +221,15 @@ struct Header: View {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
appState.sortedApps.userApps = sortedApps.userApps
|
||||
appState.sortedApps.systemApps = sortedApps.systemApps
|
||||
loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations)
|
||||
if instantSearch {
|
||||
loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations) {
|
||||
appState.reload.toggle()
|
||||
|
||||
}
|
||||
} else {
|
||||
appState.reload.toggle()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,7 +242,6 @@ struct Header: View {
|
||||
.padding(2)
|
||||
.background(Color("mode").opacity(0.1))
|
||||
.clipShape(.capsule)
|
||||
// .clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous))
|
||||
}
|
||||
}
|
||||
.onHover { hovering in
|
||||
@@ -240,6 +253,7 @@ struct Header: View {
|
||||
Spacer()
|
||||
|
||||
}
|
||||
.padding(4)
|
||||
.padding(.vertical, 8)
|
||||
.padding(.leading, 6)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||
@ObservedObject var appState: AppState
|
||||
@ObservedObject var locations: Locations
|
||||
@State private var shouldFlash = false
|
||||
private var types: [UTType] = [.fileURL]
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@State private var phase: CGFloat = 4
|
||||
@Binding var showPopover: Bool
|
||||
|
||||
public init(appState: AppState, locations: Locations, showPopover: Binding<Bool>) {
|
||||
self.appState = appState
|
||||
self.locations = locations
|
||||
_showPopover = showPopover
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
|
||||
FlashingBackground(shouldFlash: $shouldFlash)
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
ZStack {
|
||||
// Color("mode")
|
||||
// .mask(
|
||||
// Image(mini ? "pear" : "logo")
|
||||
// .resizable()
|
||||
// .scaledToFit()
|
||||
// .frame(minWidth: mini ? 104 : 300)
|
||||
// .frame(maxWidth: mini ? 104 : 500)
|
||||
// .padding(mini ? 20 : 10)
|
||||
// )
|
||||
LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||
.mask(
|
||||
Image(mini ? "pear" : "logo")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(minWidth: mini ? 104 : 300)
|
||||
.frame(maxWidth: mini ? 104 : 500)
|
||||
.padding(mini ? 20 : 10)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
// .fill(LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing))
|
||||
.strokeBorder(LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing), style: StrokeStyle(lineWidth: 3, dash: [11.0], dashPhase: phase))
|
||||
.onAppear {
|
||||
withAnimation(.linear.speed(0.5).repeat(while: ants, autoreverses: false)) {
|
||||
if ants {
|
||||
phase -= 22
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: ants) { newValue in
|
||||
withAnimation(.linear.speed(0.5).repeat(while: newValue, autoreverses: false)) {
|
||||
phase -= 22
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.onDrop(of: types, delegate: self)
|
||||
.onTapGesture {
|
||||
withAnimation(.easeInOut(duration: 0.5)) {
|
||||
appState.currentView = .apps
|
||||
}
|
||||
}
|
||||
.padding(20)
|
||||
.frame(maxWidth: mini ? 200 : .infinity)
|
||||
.frame(maxHeight: mini ? 200 : .infinity)
|
||||
|
||||
}
|
||||
|
||||
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 {
|
||||
printOS("Error: Not a valid URL.")
|
||||
return
|
||||
}
|
||||
if url.pathExtension == "app" {
|
||||
let appInfo = getAppInfo(atPath: url)
|
||||
// showPopover = false
|
||||
self.ants = false
|
||||
showAppInFiles(appInfo: appInfo!, mini: mini, appState: appState, locations: locations, showPopover: $showPopover)
|
||||
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||
// updateOnMain {
|
||||
// appState.appInfo = .empty
|
||||
// if let storedAppInfo = appState.appInfoStore.first(where: { $0.path == appInfo!.path }) {
|
||||
// appState.appInfo = storedAppInfo
|
||||
// // appState.paths = storedAppInfo.fileSize.keys.map { $0 }//storedAppInfo.files
|
||||
// appState.selectedItems = Set(storedAppInfo.files)
|
||||
// withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
// if mini {
|
||||
// showPopover.toggle()
|
||||
// } else {
|
||||
// appState.currentView = .files
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // Handle the case where the appInfo is not found in the store
|
||||
// printOS("AppInfo not found in the cached store, searching again")
|
||||
// appState.appInfo = .empty
|
||||
// appState.appInfo = appInfo!
|
||||
// findPathsForApp(appInfo: appInfo!, appState: appState, locations: locations)
|
||||
// withAnimation(Animation.easeIn(duration: 0.4)) {
|
||||
// if mini {
|
||||
// showPopover.toggle()
|
||||
// } else {
|
||||
// appState.currentView = .files
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// DispatchQueue.main.async {
|
||||
// self.ants = false
|
||||
// appState.appInfo = appInfo!
|
||||
// findPathsForApp(appState: appState, locations: locations)
|
||||
// if mini {
|
||||
// showPopover = true
|
||||
// } else {
|
||||
// appState.currentView = .files
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
printOS("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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,10 @@ struct FilesView: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center) {
|
||||
if appState.showProgress { //!self.showDetails {
|
||||
if appState.showProgress {
|
||||
VStack {
|
||||
Spacer()
|
||||
// ProgressView("Finding application files..")
|
||||
// .progressViewStyle(.linear)
|
||||
// Spacer()
|
||||
Text("Almost there, still gathering files..").font(.title3)
|
||||
Text("Searching the file system").font(.title3)
|
||||
.foregroundStyle((.gray.opacity(0.8)))
|
||||
ProgressView()
|
||||
.progressViewStyle(.linear)
|
||||
@@ -41,27 +38,29 @@ struct FilesView: View {
|
||||
VStack() {
|
||||
|
||||
// Main Group
|
||||
HStack() {
|
||||
//icon
|
||||
HStack(alignment: .center) {
|
||||
|
||||
//app icon, title, size and items
|
||||
VStack(alignment: .center) {
|
||||
HStack(alignment: .center) {
|
||||
if let appIcon = appState.appInfo.appIcon {
|
||||
Image(nsImage: appIcon)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
// .aspectRatio(contentMode: .fit)
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
.padding(.leading)
|
||||
.padding(.trailing)
|
||||
}
|
||||
//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))
|
||||
if appState.appInfo.appName.count < 5 {
|
||||
InfoButton(text: "Pearcleaner searches for files via a combination of bundle id and app name. \(appState.appInfo.appName) has a common or short app name so there might be unrelated files found. Please check the list thoroughly before uninstalling.", color: nil)
|
||||
}
|
||||
|
||||
}
|
||||
Text("\(appState.appInfo.bundleIdentifier)").font(.title3)
|
||||
.foregroundStyle((.gray.opacity(0.8)))
|
||||
@@ -69,28 +68,21 @@ struct FilesView: View {
|
||||
|
||||
Spacer()
|
||||
|
||||
VStack(alignment: .trailing, spacing: 5) {
|
||||
Text("\(formatByte(size: appState.appInfo.totalSize))").font(.title).fontWeight(.bold)
|
||||
Text("\(appState.appInfo.fileSize.count > 1 ? "\(appState.appInfo.fileSize.count) items" : "\(appState.appInfo.fileSize.count) item")").font(.callout).underline().foregroundStyle((.gray.opacity(0.8)))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Divider().padding(.bottom, 7)
|
||||
if appState.appInfo.webApp || appState.appInfo.wrapped {
|
||||
HStack(alignment: .center, spacing: 10) {
|
||||
|
||||
HStack{
|
||||
Text("Application files and folders")
|
||||
.font(.callout)
|
||||
// .foregroundStyle(Color("AccentColor"))
|
||||
.opacity(0.8)
|
||||
Spacer()
|
||||
Text("\(appState.appInfo.fileSize.count > 1 ? "\(appState.appInfo.fileSize.count) items" : "\(appState.appInfo.fileSize.count) item")").font(.callout)
|
||||
// .foregroundStyle(Color("AccentColor").opacity(0.7))
|
||||
.underline()
|
||||
}
|
||||
|
||||
HStack() {
|
||||
if appState.appInfo.webApp {
|
||||
HStack {
|
||||
Text("web")
|
||||
.font(.footnote)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
@@ -98,34 +90,33 @@ struct FilesView: View {
|
||||
.padding(2)
|
||||
.background(Color("mode").opacity(0.1))
|
||||
.clipShape(.capsule)
|
||||
Spacer()
|
||||
|
||||
}
|
||||
|
||||
if appState.appInfo.wrapped {
|
||||
Text("iOS")
|
||||
.font(.footnote)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
.frame(minWidth: 30, minHeight: 15)
|
||||
.padding(2)
|
||||
.background(Color("mode").opacity(0.1))
|
||||
.clipShape(.capsule)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if appState.appInfo.appName.count < 5 {
|
||||
WarningPopoverView(label: "Caution",
|
||||
bodyText: "Pearcleaner searches for files via 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.",
|
||||
isPresented: $showPop)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 5)
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
.padding(20)
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.top, 10)
|
||||
}
|
||||
// .padding(.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)
|
||||
// )
|
||||
)
|
||||
.padding(.bottom)
|
||||
|
||||
Divider()
|
||||
.padding()
|
||||
|
||||
ScrollView() {
|
||||
VStack {
|
||||
@@ -144,29 +135,13 @@ struct FilesView: View {
|
||||
Divider().padding(.leading, 40)
|
||||
}
|
||||
}
|
||||
// .padding(.leading, 47).padding(.trailing)
|
||||
// if let firstPath = appState.appInfo.files.first, path == firstPath {
|
||||
// FileDetailsItem(size: fileSize, icon: iconImage, path: path)
|
||||
// .padding(.trailing)
|
||||
// Divider().padding(.leading, 40).padding(.trailing)
|
||||
// } else {
|
||||
// VStack {
|
||||
// FileDetailsItem(size: fileSize, icon: iconImage, path: path)
|
||||
// if path != appState.appInfo.files.last {
|
||||
// Divider().padding(.leading, 40)
|
||||
// }
|
||||
// }
|
||||
// .padding(.leading, 47).padding(.trailing)
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
// .background(
|
||||
// RoundedRectangle(cornerRadius: 8)
|
||||
// .fill(Color("mode").opacity(colorScheme == .dark ? 0.05 : 0.05))
|
||||
// )
|
||||
|
||||
Spacer()
|
||||
|
||||
HStack() {
|
||||
|
||||
@@ -202,7 +177,7 @@ struct FilesView: View {
|
||||
|
||||
}
|
||||
|
||||
|
||||
if !appState.selectedItems.isEmpty {
|
||||
Button("Uninstall") {
|
||||
Task {
|
||||
updateOnMain {
|
||||
@@ -215,7 +190,6 @@ struct FilesView: View {
|
||||
appState.currentView = .empty
|
||||
}
|
||||
}
|
||||
|
||||
var selectedItemsArray = Array(appState.selectedItems)
|
||||
.filter { !$0.path.contains(".Trash") }
|
||||
.map { path in
|
||||
@@ -240,9 +214,6 @@ struct FilesView: View {
|
||||
showPopover = false
|
||||
updateOnMain {
|
||||
appState.isReminderVisible.toggle()
|
||||
if sentinel {
|
||||
launchctl(load: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
refreshAppList(appState.appInfo)
|
||||
@@ -253,7 +224,12 @@ struct FilesView: View {
|
||||
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Uninstall"))
|
||||
.disabled(appState.selectedItems.isEmpty)
|
||||
|
||||
} else {
|
||||
Text("No files selected to clean").font(.title).foregroundStyle(Color("mode")).opacity(0.2)
|
||||
.padding(5)
|
||||
}
|
||||
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -265,7 +241,6 @@ struct FilesView: View {
|
||||
.frame(width: 100)
|
||||
.help("Sorting Selection")
|
||||
}
|
||||
.padding(.top)
|
||||
|
||||
}
|
||||
.transition(.opacity)
|
||||
@@ -334,7 +309,6 @@ struct FileDetailsItem: View {
|
||||
.lineLimit(2)
|
||||
.truncationMode(.tail)
|
||||
.opacity(0.5)
|
||||
// .foregroundStyle(Color("AccentColor"))
|
||||
.help(path.path)
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ struct MiniMode: View {
|
||||
}
|
||||
|
||||
}
|
||||
// .padding(.leading, appState.sidebar ? 0 : 10)
|
||||
.transition(.move(edge: .leading))
|
||||
.popover(isPresented: $showPopover, arrowEdge: .trailing) {
|
||||
VStack {
|
||||
@@ -59,7 +58,7 @@ struct MiniMode: View {
|
||||
|
||||
|
||||
}
|
||||
.frame(minWidth: 300, minHeight: 335)
|
||||
.frame(minWidth: 300, minHeight: 345)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil)
|
||||
// MARK: Background for whole app
|
||||
@@ -87,21 +86,16 @@ struct MiniEmptyView: View {
|
||||
Spacer()
|
||||
|
||||
ZStack {
|
||||
LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||
.mask(
|
||||
Image(systemName: "plus.square.dashed")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 150, height: 150)
|
||||
.frame(width: 100, height: 100)
|
||||
.padding()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// DropTarget(appState: appState, locations: locations, showPopover: $showPopover)
|
||||
// .frame(maxWidth: mini ? 300 : 500)
|
||||
|
||||
Text("Drop your app here")
|
||||
.font(.title3)
|
||||
.padding(.bottom, 25)
|
||||
@@ -132,7 +126,6 @@ struct MiniEmptyView: View {
|
||||
|
||||
|
||||
}
|
||||
// .padding()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +141,7 @@ struct MiniAppView: View {
|
||||
@State private var showSys: Bool = true
|
||||
@State private var showUsr: Bool = true
|
||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@Binding var showPopover: Bool
|
||||
|
||||
var body: some View {
|
||||
@@ -174,37 +168,21 @@ struct MiniAppView: View {
|
||||
if appState.reload {
|
||||
VStack {
|
||||
Spacer()
|
||||
ProgressView("Loadings apps and files")
|
||||
ProgressView(instantSearch ? "Refreshing app list and caching files" : "Refreshing app list")
|
||||
if instantSearch {
|
||||
Image(systemName: "bolt.fill")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
.frame(width: 30, height: 30)
|
||||
.padding()
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(.vertical)
|
||||
} else {
|
||||
VStack(alignment: .center) {
|
||||
|
||||
// if appState.currentView == .apps {
|
||||
// HStack(alignment: .center, spacing: 0) {
|
||||
// Spacer()
|
||||
//
|
||||
// Button("") {
|
||||
// withAnimation(.easeInOut(duration: 0.5)) {
|
||||
// // updateOnMain {
|
||||
// appState.currentView = .empty
|
||||
// appState.appInfo = AppInfo.empty
|
||||
// showPopover = false
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
// .buttonStyle(SimpleButtonStyle(icon: "arrow.backward.square", help: "Back to Drop Zone", color: Color("mode")))
|
||||
// .padding(.leading, 10)
|
||||
// .padding(.trailing, 0)
|
||||
//
|
||||
// SearchBarMiniBottom(search: $search)
|
||||
//
|
||||
// Spacer()
|
||||
// }
|
||||
// .padding(.top, 30)
|
||||
// }
|
||||
|
||||
ScrollView {
|
||||
|
||||
LazyVStack(alignment: .leading, pinnedViews: [.sectionHeaders]) {
|
||||
@@ -253,20 +231,6 @@ struct MiniAppView: View {
|
||||
}
|
||||
}
|
||||
.transition(.move(edge: .leading))
|
||||
// .popover(isPresented: $showPopover, arrowEdge: .trailing) {
|
||||
// VStack {
|
||||
// FilesView(showPopover: $showPopover)
|
||||
// .id(appState.appInfo.id)
|
||||
// }
|
||||
// .background(
|
||||
// Rectangle()
|
||||
// .fill(Color("pop"))
|
||||
//// .background(Color("pop"))
|
||||
// .padding(-80)
|
||||
// )
|
||||
// .frame(minWidth: 600, minHeight: 500)
|
||||
//
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct TopBar: View {
|
||||
// @Binding var sidebar: Bool
|
||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||
@AppStorage("settings.general.glass") private var glass: Bool = false
|
||||
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
|
||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@EnvironmentObject var appState: AppState
|
||||
@Binding var showPopover: Bool
|
||||
@EnvironmentObject var locations: Locations
|
||||
@@ -50,7 +50,11 @@ struct TopBar: View {
|
||||
appState.currentView = .zombie
|
||||
appState.showProgress.toggle()
|
||||
showPopover.toggle()
|
||||
if instantSearch {
|
||||
reversePathsSearch(appState: appState, locations: locations)
|
||||
} else {
|
||||
loadAllPaths(allApps: appState.sortedApps.userApps + appState.sortedApps.systemApps, appState: appState, locations: locations, reverseAddon: true)
|
||||
}
|
||||
} else {
|
||||
appState.currentView = .zombie
|
||||
showPopover.toggle()
|
||||
@@ -63,7 +67,6 @@ struct TopBar: View {
|
||||
}
|
||||
|
||||
|
||||
// if appState.currentView != .empty || appState.currentView != .apps {
|
||||
if appState.currentView == .files || appState.currentView == .zombie {
|
||||
Button("") {
|
||||
withAnimation(.easeInOut(duration: 0.5)) {
|
||||
|
||||
@@ -12,6 +12,7 @@ struct TopBarMini: View {
|
||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
|
||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@Binding var search: String
|
||||
@Binding var showPopover: Bool
|
||||
@EnvironmentObject var appState: AppState
|
||||
@@ -35,7 +36,11 @@ struct TopBarMini: View {
|
||||
appState.currentView = .zombie
|
||||
appState.showProgress.toggle()
|
||||
showPopover.toggle()
|
||||
if instantSearch {
|
||||
reversePathsSearch(appState: appState, locations: locations)
|
||||
} else {
|
||||
loadAllPaths(allApps: appState.sortedApps.userApps + appState.sortedApps.systemApps, appState: appState, locations: locations, reverseAddon: true)
|
||||
}
|
||||
} else {
|
||||
appState.currentView = .zombie
|
||||
showPopover.toggle()
|
||||
@@ -70,7 +75,11 @@ struct TopBarMini: View {
|
||||
appState.currentView = .zombie
|
||||
appState.showProgress.toggle()
|
||||
showPopover.toggle()
|
||||
if instantSearch {
|
||||
reversePathsSearch(appState: appState, locations: locations)
|
||||
} else {
|
||||
loadAllPaths(allApps: appState.sortedApps.userApps + appState.sortedApps.systemApps, appState: appState, locations: locations, reverseAddon: true)
|
||||
}
|
||||
} else {
|
||||
appState.currentView = .zombie
|
||||
showPopover.toggle()
|
||||
@@ -108,7 +117,6 @@ struct SearchBarMini: View {
|
||||
HStack {
|
||||
TextField("Search", text: $search)
|
||||
.textFieldStyle(AnimatedSearchStyle(text: $search))
|
||||
// .textFieldStyle(SimpleSearchStyle(trash: true, reload: $reload, text: $search))
|
||||
}
|
||||
.frame(height: 20)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ struct ZombieView: View {
|
||||
@State private var showPop: Bool = false
|
||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@Binding var showPopover: Bool
|
||||
@Binding var search: String
|
||||
@@ -21,13 +22,11 @@ struct ZombieView: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center) {
|
||||
if appState.showProgress { //!self.showDetails {
|
||||
if appState.showProgress {
|
||||
VStack {
|
||||
Spacer()
|
||||
// ProgressView("Finding application files..")
|
||||
// .progressViewStyle(.linear)
|
||||
// Spacer()
|
||||
Text("Gathering leftover files, this might take a while..").font(.title3)
|
||||
|
||||
Text("Searching the file system").font(.title3)
|
||||
.foregroundStyle((.gray.opacity(0.8)))
|
||||
ProgressView()
|
||||
.progressViewStyle(.linear)
|
||||
@@ -42,73 +41,44 @@ struct ZombieView: View {
|
||||
|
||||
// Main Group
|
||||
HStack() {
|
||||
//icon
|
||||
// if let appIcon = appState.appInfo.appIcon {
|
||||
// Image(nsImage: appIcon)
|
||||
// .resizable()
|
||||
// .scaledToFit()
|
||||
// // .aspectRatio(contentMode: .fit)
|
||||
// .frame(width: 50, height: 50)
|
||||
// .clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
// .padding(.leading)
|
||||
// }
|
||||
//app title, size and items
|
||||
|
||||
VStack(alignment: .center) {
|
||||
|
||||
HStack(alignment: .center) {
|
||||
VStack(alignment: .leading, spacing: 5){
|
||||
HStack(alignment: .center) {
|
||||
Image(systemName: "clock.arrow.circlepath")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 50, height: 50)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.padding(.trailing)
|
||||
|
||||
VStack(alignment: .leading, spacing: 10){
|
||||
HStack {
|
||||
Text("Leftover Files").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)))
|
||||
}
|
||||
|
||||
InfoButton(text: "Leftover file search is not 100% accurate as it doesn't have any app bundles to check against. This searches for files/folders and excludes the ones that have overlap with your currently installed apps. Make sure to confirm files marked for removal are correct.", color: .red)
|
||||
Spacer()
|
||||
|
||||
Text("\(formatByte(size: appState.zombieFile.totalSize))").font(.title).fontWeight(.bold)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Divider().padding(.bottom, 7)
|
||||
|
||||
HStack{
|
||||
Text("Files and folders remaining from previously installed applications")
|
||||
.font(.callout)
|
||||
// .foregroundStyle(Color("AccentColor"))
|
||||
.opacity(0.8)
|
||||
.font(.callout).foregroundStyle((.gray.opacity(0.8)))
|
||||
}
|
||||
|
||||
Spacer()
|
||||
Text("\(appState.zombieFile.fileSize.count > 1 ? "\(appState.zombieFile.fileSize.count) items" : "\(appState.zombieFile.fileSize.count) item")").font(.callout)
|
||||
// .foregroundStyle(Color("AccentColor").opacity(0.7))
|
||||
.underline()
|
||||
|
||||
VStack(alignment: .trailing, spacing: 5) {
|
||||
Text("\(formatByte(size: appState.zombieFile.totalSize))").font(.title).fontWeight(.bold)
|
||||
Text("\(appState.zombieFile.fileSize.count == 1 ? "\(appState.zombieFile.fileSize.count) item" : "\(appState.zombieFile.fileSize.count) items")").font(.callout).underline().foregroundStyle((.gray.opacity(0.8)))
|
||||
}
|
||||
|
||||
WarningPopoverView(label: "Caution - Read",
|
||||
bodyText: "Leftover file search is not 100% accurate as it doesn't have any app bundles to check against.\nThis searches for files/folders and excludes the ones that have overlap with your currently installed apps. \nMake sure to confirm files marked for removal are correct.",
|
||||
isPresented: $showPop)
|
||||
.padding(.vertical, 5)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
.padding(20)
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.top, 10)
|
||||
}
|
||||
// .padding(.horizontal)
|
||||
.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)
|
||||
// )
|
||||
)
|
||||
|
||||
|
||||
Divider()
|
||||
.padding()
|
||||
|
||||
ScrollView() {
|
||||
LazyVStack {
|
||||
@@ -170,16 +140,10 @@ struct ZombieView: View {
|
||||
}
|
||||
|
||||
|
||||
Button("Rescan") {
|
||||
updateOnMain {
|
||||
appState.zombieFile = .empty
|
||||
appState.showProgress.toggle()
|
||||
reversePathsSearch(appState: appState, locations: locations)
|
||||
}
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "arrow.counterclockwise.circle.fill", help: "Rescan files"))
|
||||
|
||||
|
||||
|
||||
if !appState.selectedZombieItems.isEmpty {
|
||||
Button("Remove") {
|
||||
Task {
|
||||
updateOnMain {
|
||||
@@ -214,7 +178,24 @@ struct ZombieView: View {
|
||||
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Remove"))
|
||||
.disabled(appState.selectedZombieItems.isEmpty)
|
||||
} else {
|
||||
Text("No files selected to remove").font(.title).foregroundStyle(Color("mode")).opacity(0.2)
|
||||
.padding(5)
|
||||
}
|
||||
|
||||
Button("Rescan") {
|
||||
updateOnMain {
|
||||
appState.zombieFile = .empty
|
||||
appState.showProgress.toggle()
|
||||
if instantSearch {
|
||||
reversePathsSearch(appState: appState, locations: locations)
|
||||
} else {
|
||||
loadAllPaths(allApps: appState.sortedApps.userApps + appState.sortedApps.systemApps, appState: appState, locations: locations, reverseAddon: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "arrow.counterclockwise.circle.fill", help: "Rescan files"))
|
||||
|
||||
|
||||
Spacer()
|
||||
|
||||
|
||||
@@ -78,10 +78,6 @@ class NewWin: NSWindowController {
|
||||
return AnyView(PermView()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.environmentObject(appState))
|
||||
// case .restart:
|
||||
// return AnyView(RestartView()
|
||||
// .frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
// .environmentObject(appState))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,7 @@ struct PermView: View {
|
||||
Text("Pearcleaner requires the following permissions:")
|
||||
.font(.title3)
|
||||
.fontWeight(.semibold)
|
||||
// .padding(.horizontal, 20)
|
||||
.padding(.vertical)
|
||||
// .padding(.bottom)
|
||||
|
||||
|
||||
ScrollView {
|
||||
Text(" - Full Disk Access permission to find and delete files in non-user locations.\n - Accessibility permission to delete files via Finder which allows for the Undo function.\n\nAdd Pearcleaner in both Privacy panes via the + or by dragging the app over the pane. If the app is already pre-populated in the list, just toggle On. Restart app when both permissions are granted.")
|
||||
@@ -69,7 +66,6 @@ struct PermView: View {
|
||||
.padding()
|
||||
|
||||
Button(action: {
|
||||
// NewWin.close
|
||||
relaunchApp(afterDelay: 1)
|
||||
}) {
|
||||
Text("Restart")
|
||||
|
||||