mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 06:09:01 +00:00
Updates
This commit is contained in:
@@ -42,10 +42,11 @@
|
||||
C7DD49EE2BAB7F6000CCBA16 /* ReversePathsFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */; };
|
||||
C7DD49F02BABA14400CCBA16 /* Folders.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49EF2BABA14400CCBA16 /* Folders.swift */; };
|
||||
C7DE672B2BA6343D00EB1633 /* MenuBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */; };
|
||||
C7DFBDE72CAF5AD30013C825 /* CustomTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DFBDE62CAF5ACB0013C825 /* CustomTabView.swift */; };
|
||||
C7EA06332C1CBE2000F872FC /* ConditionBuilderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7EA06322C1CBE2000F872FC /* ConditionBuilderView.swift */; };
|
||||
C7ED86B12BA8A35500F13DE4 /* Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7ED86B02BA8A35500F13DE4 /* Interface.swift */; };
|
||||
C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F539372AF60865007DF1B2 /* Utilities.swift */; };
|
||||
C7F8436B2CBF066F00E3E30A /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = C7F8436A2CBF066F00E3E30A /* Localizable.xcstrings */; };
|
||||
C7F8436C2CBF066F00E3E30A /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = C7F8436A2CBF066F00E3E30A /* Localizable.xcstrings */; };
|
||||
C7FB173B2B96321300B96F9A /* AppsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FB173A2B96321300B96F9A /* AppsListView.swift */; };
|
||||
C7FEBA112BDC422200AE195F /* AppSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FEBA102BDC422200AE195F /* AppSearchView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
@@ -133,10 +134,10 @@
|
||||
C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReversePathsFetch.swift; sourceTree = "<group>"; };
|
||||
C7DD49EF2BABA14400CCBA16 /* Folders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folders.swift; sourceTree = "<group>"; };
|
||||
C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarItem.swift; sourceTree = "<group>"; };
|
||||
C7DFBDE62CAF5ACB0013C825 /* CustomTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabView.swift; sourceTree = "<group>"; };
|
||||
C7EA06322C1CBE2000F872FC /* ConditionBuilderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionBuilderView.swift; sourceTree = "<group>"; };
|
||||
C7ED86B02BA8A35500F13DE4 /* Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Interface.swift; sourceTree = "<group>"; };
|
||||
C7F539372AF60865007DF1B2 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
|
||||
C7F8436A2CBF066F00E3E30A /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
C7FB173A2B96321300B96F9A /* AppsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppsListView.swift; sourceTree = "<group>"; };
|
||||
C7FEBA102BDC422200AE195F /* AppSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSearchView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -227,6 +228,7 @@
|
||||
C77B90142AF18E7C009CC655 /* Info.plist */,
|
||||
C77B90242AF2D796009CC655 /* Pearcleaner.entitlements */,
|
||||
C77B90072AF18E2F009CC655 /* Assets.xcassets */,
|
||||
C7F8436A2CBF066F00E3E30A /* Localizable.xcstrings */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -268,7 +270,6 @@
|
||||
C77B901F2AF1B390009CC655 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C7DFBDE62CAF5ACB0013C825 /* CustomTabView.swift */,
|
||||
C77B90222AF2D616009CC655 /* FilesView.swift */,
|
||||
C71848432B8D2D600046CB13 /* ZombieView.swift */,
|
||||
C76D08542AF89CDE00D07867 /* RegularMode.swift */,
|
||||
@@ -384,6 +385,7 @@
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
ro,
|
||||
);
|
||||
mainGroup = C77B8FF72AF18E2E009CC655;
|
||||
packageReferences = (
|
||||
@@ -408,6 +410,7 @@
|
||||
files = (
|
||||
C77B90082AF18E2F009CC655 /* Assets.xcassets in Resources */,
|
||||
C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */,
|
||||
C7F8436B2CBF066F00E3E30A /* Localizable.xcstrings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -415,6 +418,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C7F8436C2CBF066F00E3E30A /* Localizable.xcstrings in Resources */,
|
||||
C7A6DBF12C9DD27200CFA042 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -438,7 +442,6 @@
|
||||
C764680F2CA7790200DC72DF /* PearGroupBox.swift in Sources */,
|
||||
C79947962C34A794007279CC /* Tips.swift in Sources */,
|
||||
C76D08482AF83C3F00D07867 /* Update.swift in Sources */,
|
||||
C7DFBDE72CAF5AD30013C825 /* CustomTabView.swift in Sources */,
|
||||
C7FB173B2B96321300B96F9A /* AppsListView.swift in Sources */,
|
||||
C77B90162AF19377009CC655 /* AppState.swift in Sources */,
|
||||
C7DD49EE2BAB7F6000CCBA16 /* ReversePathsFetch.swift in Sources */,
|
||||
@@ -538,7 +541,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APP_BUILD = 63;
|
||||
APP_VERSION = 3.9.1;
|
||||
APP_VERSION = 3.9.0;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
@@ -599,6 +602,7 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -608,7 +612,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APP_BUILD = 63;
|
||||
APP_VERSION = 3.9.1;
|
||||
APP_VERSION = 3.9.0;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
@@ -662,6 +666,7 @@
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -27,7 +27,6 @@ class AppState: ObservableObject {
|
||||
@Published var leftoverProgress: (String, Double) = ("", 0.0)
|
||||
@Published var finderExtensionEnabled: Bool = false
|
||||
@Published var showUninstallAlert: Bool = false
|
||||
@Published var oneShotMode: Bool = false
|
||||
@Published var sentinelMode: Bool = false
|
||||
@Published var showConditionBuilder: Bool = false
|
||||
|
||||
@@ -202,8 +201,8 @@ enum CurrentPage:Int, CaseIterable, Identifiable
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .applications: return "Applications"
|
||||
case .orphans: return "Orphaned Files"
|
||||
case .applications: return String(localized: "Applications")
|
||||
case .orphans: return String(localized: "Orphaned Files")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,7 +217,13 @@ enum SortOption:Int, CaseIterable, Identifiable {
|
||||
var id: Int { rawValue }
|
||||
|
||||
var title: String {
|
||||
let titles: [String] = ["App Name", "App Size", "Install Date", "Modified Date", "Last Used Date"]
|
||||
let titles: [String] = [
|
||||
String(localized: "App Name"),
|
||||
String(localized: "App Size"),
|
||||
String(localized: "Install Date"),
|
||||
String(localized: "Modified Date"),
|
||||
String(localized: "Last Used Date")
|
||||
]
|
||||
return titles[rawValue]
|
||||
}
|
||||
}
|
||||
@@ -230,17 +235,16 @@ enum CurrentTabView:Int
|
||||
case interface
|
||||
case folders
|
||||
case update
|
||||
case tips
|
||||
// case tips
|
||||
case about
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .general: return "General"
|
||||
case .interface: return "Interface"
|
||||
case .folders: return "Folders"
|
||||
case .update: return "Update"
|
||||
case .tips: return "Tips"
|
||||
case .about: return "About"
|
||||
case .general: return String(localized: "General")
|
||||
case .interface: return String(localized: "Interface")
|
||||
case .folders: return String(localized: "Folders")
|
||||
case .update: return String(localized: "Update")
|
||||
case .about: return String(localized: "About")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ let skipConditions: [SkipCondition] = [
|
||||
]
|
||||
|
||||
|
||||
// Skip files/folders during leftover file search
|
||||
// Skip files/folders during orphaned file search
|
||||
let skipReverse = ["apple", "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", "mobiledocuments", "mobile", "intentbuilderc", "loginwindow", "momc", "replayd", "sharedfilelistd", "clang", "audiocomponent", "csexattrcryptoservice", "livetranscriptionagent", "sandboxhelper", "statuskitagent", "betaenrollmentd", "contentlinkingd", "diagnosticextensionsd", "gamed", "heard", "homed", "itunescloudd", "lldb", "mds", "mediaanalysisd", "metrickitd", "mobiletimerd", "proactived", "ptpcamerad", "studentd", "talagent", "watchlistd", "apptranslocation", "xcrun", "ds_store", "caches", "crashreporter", "trash", "pearcleaner", "amsdatamigratortool", "arfilecache", "assistant", "chromium", "cloudkit", "webkit", "databases", "diagnostic", "cache", "gamekit", "homebrew", "logi", "microsoft", "mozilla", "sync", "google", "sentinel", "hexnode", "sentry", "tvappservices", "reminders", "pbs"]
|
||||
|
||||
|
||||
|
||||
@@ -45,12 +45,6 @@ class DeeplinkManager {
|
||||
}
|
||||
}
|
||||
|
||||
if oneShotMode {
|
||||
updateOnMain {
|
||||
appState.oneShotMode = true
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
printOS("No path query parameter found in the URL")
|
||||
}
|
||||
@@ -63,12 +57,6 @@ class DeeplinkManager {
|
||||
func handleAppBundle(url: URL, appState: AppState, locations: Locations) {
|
||||
let appInfo = AppInfoFetcher.getAppInfo(atPath: url)
|
||||
showAppInFiles(appInfo: appInfo!, appState: appState, locations: locations, showPopover: $showPopover)
|
||||
// Even if enabled, disable one-shot mode for app drops
|
||||
if oneShotMode {
|
||||
updateOnMain {
|
||||
appState.oneShotMode = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class Locations: ObservableObject {
|
||||
self.tempDir = tempDir
|
||||
|
||||
self.apps = Category(name: "Apps", paths: [
|
||||
// "\(home)", //MARK: Disable searching for files in user's home folder
|
||||
"\(home)",
|
||||
"\(home)/Library",
|
||||
"\(home)/Library/Application Scripts",
|
||||
"\(home)/Library/Application Support",
|
||||
|
||||
@@ -144,7 +144,7 @@ func reversePreloader(allApps: [AppInfo], appState: AppState, locations: Locatio
|
||||
@AppStorage("settings.interface.animationEnabled") var animationEnabled: Bool = true
|
||||
|
||||
updateOnMain {
|
||||
appState.leftoverProgress.0 = "Finding orphaned files, please wait..."
|
||||
appState.leftoverProgress.0 = String(localized: "Finding orphaned files, please wait...")
|
||||
}
|
||||
ReversePathsSearcher(appState: appState, locations: locations, fsm: fsm, sortedApps: allApps).reversePathsSearch {
|
||||
updateOnMain {
|
||||
@@ -153,7 +153,7 @@ func reversePreloader(allApps: [AppInfo], appState: AppState, locations: Locatio
|
||||
withAnimation(Animation.easeInOut(duration: animationEnabled ? 0.35 : 0)) {
|
||||
appState.leftoverProgress.1 = 0.0
|
||||
}
|
||||
appState.leftoverProgress.0 = "Reverse search completed successfully"
|
||||
appState.leftoverProgress.0 = String(localized: "Reverse search completed successfully")
|
||||
}
|
||||
completion()
|
||||
}
|
||||
|
||||
@@ -63,6 +63,11 @@ func findAndSetWindowFrame(named titles: [String], windowSettings: WindowSetting
|
||||
func processCLI(arguments: [String], appState: AppState, locations: Locations, fsm: FolderSettingsManager) {
|
||||
let options = Array(arguments.dropFirst()) // Remove the first argument (binary path)
|
||||
|
||||
// Launch app in terminal for debugging purposes
|
||||
func debugLaunch() {
|
||||
print("[BETA] Pearcleaner CLI | Launching App For Debugging:\n")
|
||||
}
|
||||
|
||||
// Private function to list files for uninstall, using the provided path
|
||||
func listFiles(at path: String) {
|
||||
// Convert the provided string path to a URL
|
||||
@@ -92,7 +97,7 @@ func processCLI(arguments: [String], appState: AppState, locations: Locations, f
|
||||
}
|
||||
|
||||
// Private function to list orphaned files for uninstall, using the provided path
|
||||
func listLeftoverFiles() {
|
||||
func listOrphanedFiles() {
|
||||
print("[BETA] Pearcleaner CLI | List Orphaned Files:\n")
|
||||
|
||||
// Get installed apps for filtering
|
||||
@@ -164,7 +169,7 @@ func processCLI(arguments: [String], appState: AppState, locations: Locations, f
|
||||
}
|
||||
|
||||
// Private function to remove the orphaned files
|
||||
func removeLeftoverFiles() {
|
||||
func removeOrphanedFiles() {
|
||||
print("[BETA] Pearcleaner CLI | Remove Orphaned Files:\n")
|
||||
|
||||
// Get installed apps for filtering
|
||||
@@ -184,6 +189,12 @@ func processCLI(arguments: [String], appState: AppState, locations: Locations, f
|
||||
}
|
||||
}
|
||||
|
||||
// Handle run option (-r or --run)
|
||||
if options.contains("-r") || options.contains("--run") {
|
||||
debugLaunch()
|
||||
return
|
||||
}
|
||||
|
||||
// Handle help option (-h or --help)
|
||||
if options.contains("-h") || options.contains("--help") {
|
||||
displayHelp()
|
||||
@@ -199,7 +210,7 @@ func processCLI(arguments: [String], appState: AppState, locations: Locations, f
|
||||
|
||||
// Handle --listlf or -lf option with a path argument for listing orphaned files
|
||||
if options.contains("--list-orphaned") || options.contains("-lo") {
|
||||
listLeftoverFiles()
|
||||
listOrphanedFiles()
|
||||
exit(0)
|
||||
}
|
||||
|
||||
@@ -219,7 +230,7 @@ func processCLI(arguments: [String], appState: AppState, locations: Locations, f
|
||||
|
||||
// Handle --uninstall-lf or -ulf option with a path argument for listing orphaned files
|
||||
if options.contains("--remove-orphaned") || options.contains("-ro") {
|
||||
removeLeftoverFiles()
|
||||
removeOrphanedFiles()
|
||||
exit(0)
|
||||
}
|
||||
|
||||
@@ -234,6 +245,7 @@ func displayHelp() {
|
||||
|
||||
[BETA] Pearcleaner CLI | Usage:
|
||||
|
||||
--run, -r Launch Pearcleaner in Debug mode to see console logs
|
||||
--list <path>, -l <path> List application files available for uninstall at the specified path
|
||||
--list-orphaned, -lo List orphaned files available for removal
|
||||
--uninstall <path>, -u <path> Uninstall only the application bundle at the specified path
|
||||
|
||||
@@ -0,0 +1,549 @@
|
||||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"" : {
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"(Build %@)" : {
|
||||
|
||||
},
|
||||
"/Full/Path/example-1.txt, /Full/Path/example-2.txt" : {
|
||||
|
||||
},
|
||||
"%@" : {
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"%lld" : {
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"%lld %@ %lld %@" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "%1$lld %2$@ %3$lld %4$@"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"•" : {
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"About" : {
|
||||
|
||||
},
|
||||
"Add" : {
|
||||
|
||||
},
|
||||
"Add Direct Paths:" : {
|
||||
|
||||
},
|
||||
"Add file/folder" : {
|
||||
|
||||
},
|
||||
"Add files or folders that will be ignored when searching for orphaned files. Click a path to remove it from the list." : {
|
||||
|
||||
},
|
||||
"Add folder" : {
|
||||
|
||||
},
|
||||
"Add/Save" : {
|
||||
|
||||
},
|
||||
"All checkboxes" : {
|
||||
|
||||
},
|
||||
"Always confirm the files marked for removal. In rare cases, unrelated files may be found when app names are too similar.\n\nNOTE: Pearcleaner uses AppleScript to remove files. Currently macOS does not allow AppleScript to authenticate using the fingerprint sensor, only password authentication is supported." : {
|
||||
|
||||
},
|
||||
"Animations disabled" : {
|
||||
|
||||
},
|
||||
"Animations enabled" : {
|
||||
|
||||
},
|
||||
"Announcement" : {
|
||||
|
||||
},
|
||||
"App Name" : {
|
||||
|
||||
},
|
||||
"App Size" : {
|
||||
|
||||
},
|
||||
"Appearance" : {
|
||||
|
||||
},
|
||||
"Application file is nested within subdirectories. To prevent deleting incorrect folders, Pearcleaner will leave these alone. You may manually delete the remaining folders if required." : {
|
||||
|
||||
},
|
||||
"Application Script" : {
|
||||
|
||||
},
|
||||
"Applications" : {
|
||||
|
||||
},
|
||||
"Are you sure you want to remove these files?" : {
|
||||
|
||||
},
|
||||
"calculating" : {
|
||||
|
||||
},
|
||||
"Check for Updates" : {
|
||||
|
||||
},
|
||||
"Clear" : {
|
||||
|
||||
},
|
||||
"Clear text" : {
|
||||
|
||||
},
|
||||
"Click for apps list" : {
|
||||
|
||||
},
|
||||
"Click header to change sorting order" : {
|
||||
|
||||
},
|
||||
"Click to search" : {
|
||||
|
||||
},
|
||||
"Close" : {
|
||||
|
||||
},
|
||||
"Close after uninstall" : {
|
||||
|
||||
},
|
||||
"Command Line" : {
|
||||
|
||||
},
|
||||
"Condition Builder" : {
|
||||
|
||||
},
|
||||
"Container" : {
|
||||
|
||||
},
|
||||
"Copy File Paths" : {
|
||||
|
||||
},
|
||||
"Copy Path" : {
|
||||
|
||||
},
|
||||
"Detect when apps are moved to Trash" : {
|
||||
|
||||
},
|
||||
"Disabled when menubar icon is enabled" : {
|
||||
|
||||
},
|
||||
"Dismiss" : {
|
||||
|
||||
},
|
||||
"Drop an app here" : {
|
||||
|
||||
},
|
||||
"Drop files or folders above or click to add" : {
|
||||
|
||||
},
|
||||
"Drop folders above or click to add" : {
|
||||
|
||||
},
|
||||
"Enable context menu extension for Finder" : {
|
||||
|
||||
},
|
||||
"Enabling the CLI will allow you to execute Pearcleaner actions from the Terminal. This will add pearcleaner command into /usr/local/bin so it's available directly from your PATH environment variable. Try it after enabling:\n\n> pearcleaner --help" : {
|
||||
|
||||
},
|
||||
"Enabling this extension will allow you to right click apps in Finder to quickly uninstall them with Pearcleaner" : {
|
||||
|
||||
},
|
||||
"Exclude" : {
|
||||
|
||||
},
|
||||
"Exclude Keywords:" : {
|
||||
|
||||
},
|
||||
"Exclude these files and folders from orphaned file search" : {
|
||||
|
||||
},
|
||||
"Export File Paths" : {
|
||||
|
||||
},
|
||||
"File size display options" : {
|
||||
|
||||
},
|
||||
"Finder Extension" : {
|
||||
|
||||
},
|
||||
"Finding orphaned files, please wait..." : {
|
||||
|
||||
},
|
||||
"Folders" : {
|
||||
|
||||
},
|
||||
"Functionality" : {
|
||||
|
||||
},
|
||||
"Gathering app details" : {
|
||||
|
||||
},
|
||||
"General" : {
|
||||
|
||||
},
|
||||
"GitHub" : {
|
||||
"comment" : "Github Repo",
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"GitHub Sponsors" : {
|
||||
|
||||
},
|
||||
"Hide Details" : {
|
||||
|
||||
},
|
||||
"Homebrew cleanup after uninstall" : {
|
||||
|
||||
},
|
||||
"Important" : {
|
||||
|
||||
},
|
||||
"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 app." : {
|
||||
|
||||
},
|
||||
"In mini window mode, you can have Pearcleaner startup to the Apps List view or the Drop Target view." : {
|
||||
|
||||
},
|
||||
"Include Keywords:" : {
|
||||
|
||||
},
|
||||
"Install Date" : {
|
||||
|
||||
},
|
||||
"Installed Date:" : {
|
||||
|
||||
},
|
||||
"Instructions" : {
|
||||
|
||||
},
|
||||
"Interface" : {
|
||||
|
||||
},
|
||||
"iOS" : {
|
||||
|
||||
},
|
||||
"iOS app" : {
|
||||
|
||||
},
|
||||
"item" : {
|
||||
|
||||
},
|
||||
"items" : {
|
||||
|
||||
},
|
||||
"keyword-1, keyword-2" : {
|
||||
|
||||
},
|
||||
"Last Used Date" : {
|
||||
|
||||
},
|
||||
"Last Used Date:" : {
|
||||
|
||||
},
|
||||
"Launch Pearcleaner at login" : {
|
||||
|
||||
},
|
||||
"Locations that will be searched for .app files. Click a non-default path to remove it. Default paths can't be removed." : {
|
||||
|
||||
},
|
||||
"Logical" : {
|
||||
|
||||
},
|
||||
"Made with ❤️ by Alin Lupascu" : {
|
||||
|
||||
},
|
||||
"Menubar" : {
|
||||
|
||||
},
|
||||
"Menubar icon mode" : {
|
||||
|
||||
},
|
||||
"Menubar icon preference" : {
|
||||
|
||||
},
|
||||
"Mini Configuration" : {
|
||||
|
||||
},
|
||||
"Mini window mode" : {
|
||||
|
||||
},
|
||||
"Minimalist app list rows disabled" : {
|
||||
|
||||
},
|
||||
"Minimalist app list rows enabled" : {
|
||||
|
||||
},
|
||||
"Modified Date" : {
|
||||
|
||||
},
|
||||
"Modified Date:" : {
|
||||
|
||||
},
|
||||
"More" : {
|
||||
|
||||
},
|
||||
"No files or folders added" : {
|
||||
|
||||
},
|
||||
"Not available" : {
|
||||
|
||||
},
|
||||
"of" : {
|
||||
|
||||
},
|
||||
"Open %@" : {
|
||||
|
||||
},
|
||||
"Orphaned file search is not 100% accurate as it doesn't have any uninstalled app bundles to check against for file exclusion. This does a best guess search for files/folders and excludes the ones that have overlap with your currently installed applications. Please confirm files marked for deletion really do belong to uninstalled applications." : {
|
||||
|
||||
},
|
||||
"Orphaned Files" : {
|
||||
|
||||
},
|
||||
"Pearcleaner and all of its files will be cleanly removed, are you sure?" : {
|
||||
|
||||
},
|
||||
"Pearcleaner CLI support" : {
|
||||
|
||||
},
|
||||
"Pin popover window on top" : {
|
||||
|
||||
},
|
||||
"Plist File" : {
|
||||
|
||||
},
|
||||
"Quit" : {
|
||||
|
||||
},
|
||||
"Quit Pearcleaner" : {
|
||||
|
||||
},
|
||||
"Real" : {
|
||||
|
||||
},
|
||||
"Real size type will show how much actual allocated space the file has on disk.\n\nLogical type shows the binary size. The filesystem can compress and deduplicate sectors on disk, so real size is sometimes smaller(or bigger) than logical size.\n\nFinder size is similar to if you right click > Get Info on a file in Finder, which will show both the logical and real sizes together." : {
|
||||
|
||||
},
|
||||
"Refresh" : {
|
||||
|
||||
},
|
||||
"Refresh Apps" : {
|
||||
|
||||
},
|
||||
"Refresh apps (⌘+R)" : {
|
||||
|
||||
},
|
||||
"Refresh updater" : {
|
||||
|
||||
},
|
||||
"Release Notes" : {
|
||||
|
||||
},
|
||||
"Releases" : {
|
||||
|
||||
},
|
||||
"Remaining files and folders from previous applications" : {
|
||||
|
||||
},
|
||||
"Remove" : {
|
||||
|
||||
},
|
||||
"Remove Direct Paths:" : {
|
||||
|
||||
},
|
||||
"Remove the condition from this application" : {
|
||||
|
||||
},
|
||||
"Rescan" : {
|
||||
|
||||
},
|
||||
"Reset all settings to default" : {
|
||||
|
||||
},
|
||||
"Reset Settings" : {
|
||||
|
||||
},
|
||||
"Reset Size" : {
|
||||
|
||||
},
|
||||
"Reverse search completed successfully" : {
|
||||
|
||||
},
|
||||
"Right click to reset size" : {
|
||||
|
||||
},
|
||||
"Save" : {
|
||||
|
||||
},
|
||||
"Save the condition for this application" : {
|
||||
|
||||
},
|
||||
"Search these folders for applications" : {
|
||||
|
||||
},
|
||||
"Searching the file system" : {
|
||||
|
||||
},
|
||||
"Sentinel Monitor" : {
|
||||
|
||||
},
|
||||
"Sentinel Monitor found no other files to remove" : {
|
||||
|
||||
},
|
||||
"Settings" : {
|
||||
|
||||
},
|
||||
"Show announcements badge again" : {
|
||||
|
||||
},
|
||||
"Show apps list on startup" : {
|
||||
|
||||
},
|
||||
"Show Details" : {
|
||||
|
||||
},
|
||||
"Some files/folders are not similar to the app name or bundle id, causing Pearcleaner to either not find them or find unrelated files. \nTo combat this, you may create a custom condition for each application bundle using keywords or direct paths. \n\n- Can add file/folder keywords that you want to either include or exclude in fuzzy searches. \n\n- Can explicitly add or remove a full Finder path to search results if you want a direct search." : {
|
||||
|
||||
},
|
||||
"Sorting Options" : {
|
||||
|
||||
},
|
||||
"Sponsor" : {
|
||||
|
||||
},
|
||||
"Submit a bug or feature request" : {
|
||||
|
||||
},
|
||||
"Submit New Issue" : {
|
||||
|
||||
},
|
||||
"Support" : {
|
||||
|
||||
},
|
||||
"system" : {
|
||||
|
||||
},
|
||||
"System" : {
|
||||
|
||||
},
|
||||
"Theme Mode" : {
|
||||
|
||||
},
|
||||
"This adds the file/folder to the Exclusions list. Edit the exclusions list from Settings > Folders tab" : {
|
||||
|
||||
},
|
||||
"This app is located in %@" : {
|
||||
|
||||
},
|
||||
"This is a web app" : {
|
||||
|
||||
},
|
||||
"This is a wrapped iOS app" : {
|
||||
|
||||
},
|
||||
"This setting will affect Pearcleaner whether you're running in menubar mode or regular mode. If you disable menubar icon, you might want to disable this as well so Pearcleaner doesn't start on login." : {
|
||||
|
||||
},
|
||||
"Toggling between modes will reset the window frames to their default size/position" : {
|
||||
|
||||
},
|
||||
"Tools" : {
|
||||
"comment" : "Tools Menu"
|
||||
},
|
||||
"Total size of files:" : {
|
||||
|
||||
},
|
||||
"Transparent material" : {
|
||||
|
||||
},
|
||||
"Type to search" : {
|
||||
|
||||
},
|
||||
"Undo Removal" : {
|
||||
|
||||
},
|
||||
"Uninstall" : {
|
||||
|
||||
},
|
||||
"Uninstall confirmation alerts" : {
|
||||
|
||||
},
|
||||
"Uninstall Pearcleaner" : {
|
||||
|
||||
},
|
||||
"Update" : {
|
||||
|
||||
},
|
||||
"Update Frequency" : {
|
||||
|
||||
},
|
||||
"user" : {
|
||||
|
||||
},
|
||||
"User" : {
|
||||
|
||||
},
|
||||
"v%@" : {
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"Version %@" : {
|
||||
|
||||
},
|
||||
"View" : {
|
||||
|
||||
},
|
||||
"View in Finder" : {
|
||||
|
||||
},
|
||||
"View Issues" : {
|
||||
|
||||
},
|
||||
"View project contributors" : {
|
||||
|
||||
},
|
||||
"View Releases" : {
|
||||
|
||||
},
|
||||
"View releases on GitHub" : {
|
||||
|
||||
},
|
||||
"View Repository" : {
|
||||
|
||||
},
|
||||
"Warning" : {
|
||||
|
||||
},
|
||||
"Warning!" : {
|
||||
|
||||
},
|
||||
"web" : {
|
||||
|
||||
},
|
||||
"Web app" : {
|
||||
|
||||
},
|
||||
"When applications are moved to Trash, Pearcleaner will launch and find related files and folders for deletion." : {
|
||||
|
||||
},
|
||||
"When deleting files using the Trash button, you can prevent accidental deletions by showing an alert before proceeding with the action." : {
|
||||
|
||||
},
|
||||
"When homebrew cleanup is enabled, Pearcleaner will check if the app you are removing was installed via homebrew and launch Terminal.app to execute a brew uninstall and cleanup command to let homebrew know that the app is removed. This way your homebrew list will be synced up correctly and caching will be removed. Terminal.app is required since some apps need sudo permissions to remove services and files placed in system folders. Since other terminal apps don't support applescript and/or the 'do script' command, I opted to use the default macOS Terminal app for this.\n\nNOTE: If you undo the file delete with CMD+Z, the files will be put back but homebrew will not be aware of it. To get the homebrew list back in sync you'd need to run:\n\n> brew install APPNAME --force" : {
|
||||
|
||||
},
|
||||
"When menubar icon is enabled, the main app window and dock icon will be disabled since the app will be put in accessory mode." : {
|
||||
|
||||
},
|
||||
"When this mode is enabled, clicking the Uninstall button to remove an app will also close Pearcleaner right after.\nThis only affects Pearcleaner when it is opened via external means, like Sentinel Trash Monitor, Finder extension or a Deep Link.\nThis allows for single use of the app for a quick uninstall. When Pearcleaner is opened normally, this setting is ignored and will work as usual." : {
|
||||
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
@@ -75,7 +75,7 @@ struct AboutSettingsTab: View {
|
||||
Button(""){
|
||||
NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner/issues/new/choose")!)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "paperplane", help: String(localized: "View")))
|
||||
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ struct AboutSettingsTab: View {
|
||||
Button(""){
|
||||
NSWorkspace.shared.open(sponsor.url)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "link", help: "View", padding: 5))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "link", help: String(localized: "View")))
|
||||
.padding(.trailing)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ struct FolderSettingsTab: View {
|
||||
PearGroupBox(header: {
|
||||
HStack(alignment: .center, spacing: 0) {
|
||||
Text("Search these folders for applications").font(.title2)
|
||||
InfoButton(text: "Locations that will be searched for .app files. Click a non-default path to remove it. Default paths can't be removed.")
|
||||
InfoButton(text: String(localized: "Locations that will be searched for .app files. Click a non-default path to remove it. Default paths can't be removed."))
|
||||
.padding(.leading, 5)
|
||||
Spacer()
|
||||
}
|
||||
@@ -99,18 +99,18 @@ struct FolderSettingsTab: View {
|
||||
Button("") {
|
||||
selectFolder()
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "plus.circle", help: "Add folder", size: 16, rotate: true))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "plus.circle", help: String(localized: "Add folder"), size: 16, rotate: true))
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// === Leftover Folders============================================================================================
|
||||
// === Orphaned Folders============================================================================================
|
||||
|
||||
PearGroupBox(header: {
|
||||
HStack(spacing: 0) {
|
||||
Text("Exclude these files and folders from leftover search").font(.title2)
|
||||
InfoButton(text: "Add files or folders that will be ignored when searching for orphaned files. Click a path to remove it from the list.")
|
||||
Text("Exclude these files and folders from orphaned file search").font(.title2)
|
||||
InfoButton(text: String(localized: "Add files or folders that will be ignored when searching for orphaned files. Click a path to remove it from the list."))
|
||||
.padding(.leading, 5)
|
||||
Spacer()
|
||||
}
|
||||
@@ -186,7 +186,7 @@ struct FolderSettingsTab: View {
|
||||
Button("") {
|
||||
selectFilesFoldersZ()
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "plus.circle", help: "Add file/folder", size: 16, rotate: true))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "plus.circle", help: String(localized: "Add file/folder"), size: 16, rotate: true))
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ struct GeneralSettingsTab: View {
|
||||
Text("Homebrew cleanup after uninstall")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary.opacity(1))
|
||||
InfoButton(text: "When homebrew cleanup is enabled, Pearcleaner will check if the app you are removing was installed via homebrew and launch Terminal.app to execute a brew uninstall and cleanup command to let homebrew know that the app is removed. This way your homebrew list will be synced up correctly and caching will be removed. Terminal.app is required since some apps need sudo permissions to remove services and files placed in system folders. Since other terminal apps don't support applescript and/or the 'do script' command, I opted to use the default macOS Terminal app for this.\n\nNOTE: If you undo the file delete with CMD+Z, the files will be put back but homebrew will not be aware of it. To get the homebrew list back in sync you'd need to run:\n\n> brew install APPNAME --force")
|
||||
InfoButton(text: String(localized: "When homebrew cleanup is enabled, Pearcleaner will check if the app you are removing was installed via homebrew and launch Terminal.app to execute a brew uninstall and cleanup command to let homebrew know that the app is removed. This way your homebrew list will be synced up correctly and caching will be removed. Terminal.app is required since some apps need sudo permissions to remove services and files placed in system folders. Since other terminal apps don't support applescript and/or the 'do script' command, I opted to use the default macOS Terminal app for this.\n\nNOTE: If you undo the file delete with CMD+Z, the files will be put back but homebrew will not be aware of it. To get the homebrew list back in sync you'd need to run:\n\n> brew install APPNAME --force"))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,7 +72,7 @@ struct GeneralSettingsTab: View {
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
|
||||
InfoButton(text: "When deleting files using the Trash button, you can prevent accidental deletions by showing an alert before proceeding with the action.")
|
||||
InfoButton(text: String(localized: "When deleting files using the Trash button, you can prevent accidental deletions by showing an alert before proceeding with the action."))
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $confirmAlert, label: {
|
||||
@@ -96,7 +96,7 @@ struct GeneralSettingsTab: View {
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
|
||||
InfoButton(text: "When this mode is enabled, clicking the Uninstall button to remove an app will also close Pearcleaner right after.\nThis only affects Pearcleaner when it is opened via external means, like Sentinel Trash Monitor, Finder extension or a Deep Link.\nThis allows for single use of the app for a quick uninstall. When Pearcleaner is opened normally, this setting is ignored and will work as usual.")
|
||||
InfoButton(text: String(localized: "When this mode is enabled, clicking the Uninstall button to remove an app will also close Pearcleaner right after.\nThis only affects Pearcleaner when it is opened via external means, like Sentinel Trash Monitor, Finder extension or a Deep Link.\nThis allows for single use of the app for a quick uninstall. When Pearcleaner is opened normally, this setting is ignored and will work as usual."))
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $oneShotMode, label: {
|
||||
@@ -144,7 +144,7 @@ struct GeneralSettingsTab: View {
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
InfoButton(text: "Real size type will show how much actual allocated space the file has on disk.\n\nLogical type shows the binary size. The filesystem can compress and deduplicate sectors on disk, so real size is sometimes smaller(or bigger) than logical size.\n\nFinder size is similar to if you right click > Get Info on a file in Finder, which will show both the logical and real sizes together.")
|
||||
InfoButton(text: String(localized: "Real size type will show how much actual allocated space the file has on disk.\n\nLogical type shows the binary size. The filesystem can compress and deduplicate sectors on disk, so real size is sometimes smaller(or bigger) than logical size.\n\nFinder size is similar to if you right click > Get Info on a file in Finder, which will show both the logical and real sizes together."))
|
||||
Spacer()
|
||||
Picker("", selection: $sizeType) {
|
||||
Text("Real")
|
||||
@@ -179,7 +179,7 @@ struct GeneralSettingsTab: View {
|
||||
Text("Detect when apps are moved to Trash")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
InfoButton(text: "When applications are moved to Trash, Pearcleaner will launch and find related files and folders for deletion.")
|
||||
InfoButton(text: String(localized: "When applications are moved to Trash, Pearcleaner will launch and find related files and folders for deletion."))
|
||||
Spacer()
|
||||
|
||||
Toggle(isOn: $sentinel, label: {
|
||||
@@ -212,7 +212,7 @@ struct GeneralSettingsTab: View {
|
||||
Text("Enable context menu extension for Finder")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
InfoButton(text: "Enabling this extension will allow you to right click apps in Finder to quickly uninstall them with Pearcleaner")
|
||||
InfoButton(text: String(localized: "Enabling this extension will allow you to right click apps in Finder to quickly uninstall them with Pearcleaner"))
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -252,7 +252,7 @@ struct GeneralSettingsTab: View {
|
||||
Text("Pearcleaner CLI support")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
InfoButton(text: "Enabling the CLI will allow you to execute Pearcleaner actions from the Terminal. This will add pearcleaner command into /usr/local/bin so it's available directly from your PATH environment variable. Try it after enabling:\n\n> pearcleaner --help")
|
||||
InfoButton(text: String(localized: "Enabling the CLI will allow you to execute Pearcleaner actions from the Terminal. This will add pearcleaner command into /usr/local/bin so it's available directly from your PATH environment variable. Try it after enabling:\n\n> pearcleaner --help"))
|
||||
Spacer()
|
||||
|
||||
Toggle(isOn: $isCLISymlinked, label: {
|
||||
|
||||
@@ -83,8 +83,7 @@ struct InterfaceSettingsTab: View {
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.primary)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(animationEnabled ? "Animations enabled" : "Animations disabled")")
|
||||
.font(.callout)
|
||||
Text(animationEnabled ? String(localized: "Animations enabled") : String(localized: "Animations disabled")) .font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
Spacer()
|
||||
@@ -103,7 +102,7 @@ struct InterfaceSettingsTab: View {
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.primary)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(minimalEnabled ? "Minimalist app list rows enabled" : "Minimalist app list rows disabled")")
|
||||
Text(minimalEnabled ? String(localized: "Minimalist app list rows enabled") : String(localized: "Minimalist app list rows disabled"))
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
@@ -153,13 +152,13 @@ struct InterfaceSettingsTab: View {
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
InfoButton(text: "Toggling between modes will reset the window frames to their default size/position")
|
||||
InfoButton(text: String(localized: "Toggling between modes will reset the window frames to their default size/position"))
|
||||
Spacer()
|
||||
Toggle(isOn: $mini, label: {
|
||||
})
|
||||
.toggleStyle(.switch)
|
||||
.disabled(menubarEnabled)
|
||||
.help(menubarEnabled ? "Disabled when menubar icon is enabled" : "")
|
||||
.help(menubarEnabled ? String(localized: "Disabled when menubar icon is enabled") : String(localized: ""))
|
||||
.onChange(of: mini) { newVal in
|
||||
if mini {
|
||||
appState.currentView = miniView ? .apps : .empty
|
||||
@@ -212,7 +211,7 @@ struct InterfaceSettingsTab: View {
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
|
||||
InfoButton(text: "In mini window mode, you can have Pearcleaner startup to the Apps List view or the Drop Target view.")
|
||||
InfoButton(text: String(localized: "In mini window mode, you can have Pearcleaner startup to the Apps List view or the Drop Target view."))
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $miniView, label: {
|
||||
@@ -238,7 +237,7 @@ struct InterfaceSettingsTab: View {
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
|
||||
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 app.")
|
||||
InfoButton(text: String(localized: "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 app."))
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $popoverStay, label: {
|
||||
@@ -265,7 +264,7 @@ struct InterfaceSettingsTab: View {
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
InfoButton(text: "When menubar icon is enabled, the main app window and dock icon will be disabled since the app will be put in accessory mode.")
|
||||
InfoButton(text: String(localized: "When menubar icon is enabled, the main app window and dock icon will be disabled since the app will be put in accessory mode."))
|
||||
Spacer()
|
||||
Toggle(isOn: $menubarEnabled, label: {
|
||||
})
|
||||
@@ -331,7 +330,7 @@ struct InterfaceSettingsTab: View {
|
||||
.font(.callout)
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
InfoButton(text: "This setting will affect Pearcleaner whether you're running in menubar mode or regular mode. If you disable menubar icon, you might want to disable this as well so Pearcleaner doesn't start on login.")
|
||||
InfoButton(text: String(localized: "This setting will affect Pearcleaner whether you're running in menubar mode or regular mode. If you disable menubar icon, you might want to disable this as well so Pearcleaner doesn't start on login."))
|
||||
Spacer()
|
||||
Toggle(isOn: $isLaunchAtLoginEnabled, label: {
|
||||
})
|
||||
|
||||
@@ -44,22 +44,22 @@ struct SettingsView: View {
|
||||
.padding(.bottom, 8)
|
||||
.padding(.horizontal, 9)
|
||||
|
||||
SidebarItemView(title: "General", systemImage: "gear", isSelected: selectedTab == .general) {
|
||||
SidebarItemView(title: CurrentTabView.general.title, systemImage: "gear", isSelected: selectedTab == .general) {
|
||||
selectedTab = .general
|
||||
}
|
||||
SidebarItemView(title: "Interface", systemImage: "macwindow", isSelected: selectedTab == .interface) {
|
||||
SidebarItemView(title: CurrentTabView.interface.title, systemImage: "macwindow", isSelected: selectedTab == .interface) {
|
||||
selectedTab = .interface
|
||||
}
|
||||
SidebarItemView(title: "Folders", systemImage: "folder", isSelected: selectedTab == .folders) {
|
||||
SidebarItemView(title: CurrentTabView.folders.title, systemImage: "folder", isSelected: selectedTab == .folders) {
|
||||
selectedTab = .folders
|
||||
}
|
||||
SidebarItemView(title: "Update", systemImage: "cloud", isSelected: selectedTab == .update) {
|
||||
SidebarItemView(title: CurrentTabView.update.title, systemImage: "cloud", isSelected: selectedTab == .update) {
|
||||
selectedTab = .update
|
||||
}
|
||||
SidebarItemView(title: "Tips", systemImage: "star", isSelected: selectedTab == .tips) {
|
||||
selectedTab = .tips
|
||||
}
|
||||
SidebarItemView(title: "About", systemImage: "info.circle", isSelected: selectedTab == .about) {
|
||||
// SidebarItemView(title: CurrentTabView.tips.title, systemImage: "star", isSelected: selectedTab == .tips) {
|
||||
// selectedTab = .tips
|
||||
// }
|
||||
SidebarItemView(title: CurrentTabView.about.title, systemImage: "info.circle", isSelected: selectedTab == .about) {
|
||||
selectedTab = .about
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ struct SettingsView: View {
|
||||
Button("") {
|
||||
resetUserDefaults()
|
||||
}
|
||||
.buttonStyle(ResetSettingsButtonStyle(isResetting: $isResetting, label: "Reset Settings", help: "Reset all settings to default"))
|
||||
.buttonStyle(ResetSettingsButtonStyle(isResetting: $isResetting, label: String(localized: "Reset Settings"), help: String(localized: "Reset all settings to default")))
|
||||
.disabled(isResetting)
|
||||
|
||||
|
||||
@@ -102,8 +102,8 @@ struct SettingsView: View {
|
||||
case .update:
|
||||
UpdateSettingsTab()
|
||||
.environmentObject(updater)
|
||||
case .tips:
|
||||
TipsSettingsTab()
|
||||
// case .tips:
|
||||
// TipsSettingsTab()
|
||||
case .about:
|
||||
AboutSettingsTab()
|
||||
}
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
////
|
||||
//// Tips.swift
|
||||
//// Pearcleaner
|
||||
////
|
||||
//// Created by Alin Lupascu on 7/2/24.
|
||||
////
|
||||
//
|
||||
// Tips.swift
|
||||
// Pearcleaner
|
||||
//
|
||||
// Created by Alin Lupascu on 7/2/24.
|
||||
//import SwiftUI
|
||||
//import Foundation
|
||||
//import AlinFoundation
|
||||
//
|
||||
//struct TipsSettingsTab: View {
|
||||
// @EnvironmentObject var appState: AppState
|
||||
// @EnvironmentObject var themeManager: ThemeManager
|
||||
// @AppStorage("settings.general.glass") private var glass: Bool = false
|
||||
//
|
||||
// var body: some View {
|
||||
// VStack {
|
||||
//
|
||||
// PearGroupBox(header: { Text("Tips And Tricks").font(.title2) }, content: {
|
||||
// ScrollView {
|
||||
// VStack(alignment: .leading, spacing: 15) {
|
||||
// Text("1. Clicking an app will perform a search for files and folders, which will be displayed in the Files view")
|
||||
// Text("2. The Files view will show app details and the found files along with a toolbar above the file list which shows related badges for the app, allows checking/unchecking all files and sorting alphabetically or by size")
|
||||
// Text("3. Clicking the Trash button on the Files view will remove the selected files and folders only")
|
||||
// Text("4. After deletion, you can hit CMD + Z to undo while Pearcleaner or Finder is focused")
|
||||
// Text("5. While on the Files view for an app, you can open the Condition Builder with CMD + B or from the Tools menubar item Instructions on using Condition Builder are available on the popup sheet")
|
||||
// Text("6. On the Files view again, you can hit CMD + E to export a list of the found files or from the Tools menubar item")
|
||||
// Text("7. CMD + U will check for updates manually")
|
||||
// Text("8. CMD + R will refresh the app list. This can also be done from the refresh button in the search bar")
|
||||
// Text("9. In the search bar menu button, you will also find Orphaned Files which will find files orphaned by previously uninstalled applications")
|
||||
// Text("10. You can enable a menubar icon from Settings")
|
||||
// Text("11. You can enable mini mode version of the UI from Settings")
|
||||
// Text("12. You can enable a Finder extension from Settings which allows you to uninstall apps by right clicking them in Finder")
|
||||
// Text("13. You can enable Homebrew cleanup from Settings")
|
||||
// Text("14. You can change the app theme colors from Settings")
|
||||
// Text("15. When there's new features available, an announcement badge will show at the top of the app list. Same for app app updates or missing permissions")
|
||||
// Text("16. You can disable animations in the Settings Interface tab plus a few more other options like confirmation dialog when removing files")
|
||||
// }
|
||||
// .padding()
|
||||
// }
|
||||
// .scrollIndicators(.visible)
|
||||
// .frame(height: 530)
|
||||
// .frame(maxWidth: .infinity)
|
||||
// })
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
|
||||
|
||||
import SwiftUI
|
||||
import Foundation
|
||||
import AlinFoundation
|
||||
|
||||
struct TipsSettingsTab: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@EnvironmentObject var themeManager: ThemeManager
|
||||
@AppStorage("settings.general.glass") private var glass: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
|
||||
PearGroupBox(header: { Text("Tips And Tricks").font(.title2) }, content: {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 15) {
|
||||
Text("1. Clicking an app will perform a search for files and folders, which will be displayed in the Files view")
|
||||
Text("2. The Files view will show app details and the found files along with a toolbar above the file list which shows related badges for the app, allows checking/unchecking all files and sorting alphabetically or by size")
|
||||
Text("3. Clicking the Trash button on the Files view will remove the selected files and folders only")
|
||||
Text("4. After deletion, you can hit CMD + Z to undo while Pearcleaner or Finder is focused")
|
||||
Text("5. While on the Files view for an app, you can open the Condition Builder with CMD + B or from the Tools menubar item Instructions on using Condition Builder are available on the popup sheet")
|
||||
Text("6. On the Files view again, you can hit CMD + E to export a list of the found files or from the Tools menubar item")
|
||||
Text("7. CMD + U will check for updates manually")
|
||||
Text("8. CMD + R will refresh the app list. This can also be done from the refresh button in the search bar")
|
||||
Text("9. In the search bar menu button, you will also find Orphaned Files which will find files leftover by previously uninstalled applications")
|
||||
Text("10. You can enable a menubar icon from Settings")
|
||||
Text("11. You can enable mini mode version of the UI from Settings")
|
||||
Text("12. You can enable a Finder extension from Settings which allows you to uninstall apps by right clicking them in Finder")
|
||||
Text("13. You can enable Homebrew cleanup from Settings")
|
||||
Text("14. You can change the app theme colors from Settings")
|
||||
Text("15. When there's new features available, an announcement badge will show at the top of the app list. Same for app app updates or missing permissions")
|
||||
Text("16. You can disable animations in the Settings Interface tab plus a few more other options like confirmation dialog when removing files")
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.scrollIndicators(.visible)
|
||||
.frame(height: 530)
|
||||
.frame(maxWidth: .infinity)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -38,20 +38,19 @@ struct UpdateSettingsTab: View {
|
||||
Button(""){
|
||||
updater.checkForUpdatesForce(showSheet: false)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.uturn.left.circle", label: "Refresh", help: "Refresh updater"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.uturn.left.circle", label: String(localized: "Refresh"), help: String(localized: "Refresh updater")))
|
||||
|
||||
|
||||
Button(""){
|
||||
updater.resetAnnouncementAlert()
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "star", label: "Announcement", help: "Show announcements badge again"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "star", label: String(localized: "Announcement"), help: String(localized: "Show announcements badge again")))
|
||||
|
||||
|
||||
Button(""){
|
||||
NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner/releases")!)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "link", label: "Releases", help: "View releases on GitHub"))
|
||||
|
||||
.buttonStyle(SimpleButtonStyle(icon: "link", label: String(localized: "Releases"), help: String(localized: "View releases on GitHub")))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ struct AppListItems: View {
|
||||
let appInfo: AppInfo
|
||||
var isSelected: Bool { appState.appInfo.path == appInfo.path }
|
||||
@State private var hoveredItemPath: URL? = nil
|
||||
@State private var bundleSize: Int64 = 0
|
||||
|
||||
var body: some View {
|
||||
|
||||
@@ -70,7 +69,7 @@ struct AppListItems: View {
|
||||
.opacity(0.5)
|
||||
Text("•").font(.footnote).opacity(0.5)
|
||||
|
||||
Text(bundleSize == 0 ? "calculating" : "\(formatByte(size: bundleSize).human)")
|
||||
Text(appInfo.bundleSize == 0 ? String(localized: "calculating") : "\(formatByte(size: appInfo.bundleSize).human)")
|
||||
.font(.footnote)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
@@ -109,6 +108,20 @@ struct AppListItems: View {
|
||||
.foregroundStyle(.primary.opacity(0.5))
|
||||
}
|
||||
|
||||
if isSelected && !(mini || menubarEnabled) {
|
||||
Button("Close") {
|
||||
withAnimation(Animation.easeInOut(duration: animationEnabled ? 0.35 : 0)) {
|
||||
updateOnMain {
|
||||
appState.appInfo = .empty
|
||||
appState.selectedItems = []
|
||||
appState.currentView = miniView ? .apps : .empty
|
||||
showPopover = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: String(localized: "Close"), size: 16))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -117,7 +130,6 @@ struct AppListItems: View {
|
||||
.frame(height: 35)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 5)
|
||||
// .help(appInfo.appName)
|
||||
.onHover { hovering in
|
||||
withAnimation(Animation.easeInOut(duration: animationEnabled ? 0.35 : 0)) {
|
||||
self.isHovered = hovering
|
||||
|
||||
@@ -78,7 +78,7 @@ struct AppSearchView: View {
|
||||
reloadAppsList(appState: appState, fsm: fsm)
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.counterclockwise.circle", help: "Refresh apps (⌘+R)", size: 16))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.counterclockwise.circle", help: String(localized: "Refresh apps (⌘+R)"), size: 16))
|
||||
}
|
||||
|
||||
SearchBar(search: $search, darker: (mini || menubarEnabled) ? false : true, glass: glass, sidebar: false)
|
||||
@@ -88,7 +88,7 @@ struct AppSearchView: View {
|
||||
Button("More") {
|
||||
self.showMenu.toggle()
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "ellipsis.circle", help: "More", size: 16, rotate: false))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "ellipsis.circle", help: String(localized: "More"), size: 16, rotate: false))
|
||||
.popover(isPresented: $showMenu) {
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
@@ -136,7 +136,7 @@ struct AppSearchView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Orphaned Files", help: "Orphaned Files", size: 5))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: String(localized: "Orphaned Files"), help: String(localized: "Orphaned Files"), size: 5))
|
||||
|
||||
|
||||
if #available(macOS 14.0, *) {
|
||||
@@ -151,15 +151,14 @@ struct AppSearchView: View {
|
||||
}
|
||||
showMenu = false
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Settings", help: "Settings", size: 5))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: String(localized: "Settings"), help: String(localized: "Settings"), size: 5))
|
||||
}
|
||||
|
||||
if menubarEnabled {
|
||||
Button("Quit") {
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Quit", help: "Quit Pearcleaner", size: 5))
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: String(localized: "Quit"), help: String(localized: "Quit Pearcleaner"), size: 5)) }
|
||||
|
||||
}
|
||||
.padding()
|
||||
@@ -274,7 +273,7 @@ struct SimpleSearchStyle: TextFieldStyle {
|
||||
if text.isEmpty {
|
||||
HStack {
|
||||
Spacer()
|
||||
Text(isFocused ? "Type to search" : "Click to search")
|
||||
Text(isFocused ? String(localized: "Type to search") : String(localized: "Click to search"))
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
@@ -291,7 +290,7 @@ struct SimpleSearchStyle: TextFieldStyle {
|
||||
Button("") {
|
||||
text = ""
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "delete.left.fill", help: "Clear text", size: 14, padding: padding))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "delete.left.fill", help: String(localized: "Clear text"), size: 14, padding: padding))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,13 +23,12 @@ struct AppsListView: View {
|
||||
let filteredSystemApps = filteredApps.filter { $0.system }
|
||||
|
||||
if !filteredUserApps.isEmpty {
|
||||
SectionView(title: "User", count: filteredUserApps.count, apps: filteredUserApps, search: $search, showPopover: $showPopover)
|
||||
SectionView(title: String(localized: "User"), count: filteredUserApps.count, apps: filteredUserApps, search: $search, showPopover: $showPopover)
|
||||
}
|
||||
|
||||
|
||||
if !filteredSystemApps.isEmpty {
|
||||
SectionView(title: "System", count: filteredSystemApps.count, apps: filteredSystemApps, search: $search, showPopover: $showPopover)
|
||||
}
|
||||
SectionView(title: String(localized: "System"), count: filteredSystemApps.count, apps: filteredSystemApps, search: $search, showPopover: $showPopover) }
|
||||
}
|
||||
.padding(.top, !mini ? 4 : 0)
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ struct ConditionBuilderView: View {
|
||||
Button("Close") {
|
||||
showAlert = false
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: "Close"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: String(localized: "Close")))
|
||||
}
|
||||
|
||||
Divider()
|
||||
Spacer()
|
||||
InfoButton(text: "Some files/folders are not similar to the app name or bundle id, causing Pearcleaner to either not find them or find unrelated files. \nTo combat this, you may create a custom condition for each application bundle using keywords or direct paths. \n\n- Can add file/folder keywords that you want to either include or exclude in fuzzy searches. \n\n- Can explicitly add or remove a full Finder path to search results if you want a direct search.", label: "Instructions", edge: .bottom)
|
||||
InfoButton(text: String(localized: "Some files/folders are not similar to the app name or bundle id, causing Pearcleaner to either not find them or find unrelated files. \nTo combat this, you may create a custom condition for each application bundle using keywords or direct paths. \n\n- Can add file/folder keywords that you want to either include or exclude in fuzzy searches. \n\n- Can explicitly add or remove a full Finder path to search results if you want a direct search."), label: String(localized: "Instructions"), edge: .bottom)
|
||||
Spacer()
|
||||
|
||||
VStack {
|
||||
@@ -48,7 +48,7 @@ struct ConditionBuilderView: View {
|
||||
Button("Clear") {
|
||||
include = ""
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "xmark.circle.fill", help: "Clear", size: 15))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "xmark.circle.fill", help: String(localized: "Clear"), size: 15))
|
||||
}
|
||||
|
||||
HStack {
|
||||
@@ -61,7 +61,7 @@ struct ConditionBuilderView: View {
|
||||
Button("Clear") {
|
||||
exclude = ""
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "xmark.circle.fill", help: "Clear", size: 15))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "xmark.circle.fill", help: String(localized: "Clear"), size: 15))
|
||||
}
|
||||
|
||||
HStack {
|
||||
@@ -74,7 +74,7 @@ struct ConditionBuilderView: View {
|
||||
Button("Clear") {
|
||||
paths = ""
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "xmark.circle.fill", help: "Clear", size: 15))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "xmark.circle.fill", help: String(localized: "Clear"), size: 15))
|
||||
}
|
||||
HStack {
|
||||
Text("Remove Direct Paths:").font(.callout)
|
||||
@@ -86,7 +86,7 @@ struct ConditionBuilderView: View {
|
||||
Button("Clear") {
|
||||
pathsEx = ""
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "xmark.circle.fill", help: "Clear", size: 15))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "xmark.circle.fill", help: String(localized: "Clear"), size: 15))
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
@@ -102,7 +102,7 @@ struct ConditionBuilderView: View {
|
||||
let newCondition = Condition(bundle_id: bundle, include: include.toConditionFormat(), exclude: exclude.toConditionFormat(), includeForce: paths.toConditionFormat(), excludeForce: pathsEx.toConditionFormat())
|
||||
ConditionManager.shared.saveCondition(newCondition)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "plus.square.fill", label: conditionExists ? "Save" : "Add", help: "Save the condition for this application"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "plus.square.fill", label: conditionExists ? String(localized: "Save") : String(localized: "Add"), help: String(localized: "Save the condition for this application")))
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -114,7 +114,7 @@ struct ConditionBuilderView: View {
|
||||
pathsEx = ""
|
||||
ConditionManager.shared.deleteCondition(bundle_id: bundle)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "minus.square.fill", label: "Remove", help: "Remove the condition from this application"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "minus.square.fill", label: String(localized: "Remove"), help: String(localized: "Remove the condition from this application")))
|
||||
.disabled(!conditionExists)
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
//
|
||||
// CustomTabView.swift
|
||||
// Pearcleaner
|
||||
//
|
||||
// Created by Alin Lupascu on 10/3/24.
|
||||
//
|
||||
import SwiftUI
|
||||
|
||||
public struct CustomTabView: View {
|
||||
private let titles: [String]
|
||||
private let icons: [String]
|
||||
private let tabViews: [AnyView]
|
||||
|
||||
@State private var selection = 0
|
||||
@State private var indexHovered = -1
|
||||
|
||||
public init(content: [(title: String, icon: String, view: AnyView)]) {
|
||||
self.titles = content.map{ $0.title }
|
||||
self.icons = content.map{ $0.icon }
|
||||
self.tabViews = content.map{ $0.view }
|
||||
}
|
||||
|
||||
public var tabBar: some View {
|
||||
HStack {
|
||||
Spacer()
|
||||
ForEach(0..<titles.count, id: \.self) { index in
|
||||
|
||||
HStack {
|
||||
Image(systemName: self.icons[index])
|
||||
.font(.title2)
|
||||
Text(self.titles[index])
|
||||
}
|
||||
// .frame(height: 30)
|
||||
.padding(5)
|
||||
.background(Color.gray.opacity(((self.selection == index) || (self.indexHovered == index)) ? 0.3 : 0),
|
||||
in: RoundedRectangle(cornerRadius: 8, style: .continuous))
|
||||
|
||||
.frame(height: 40)
|
||||
.padding(.horizontal, 0)
|
||||
.foregroundColor(self.selection == index ? .accent : .primary.opacity(0.8))
|
||||
.onHover(perform: { hovering in
|
||||
if hovering {
|
||||
indexHovered = index
|
||||
} else {
|
||||
indexHovered = -1
|
||||
}
|
||||
})
|
||||
.onTapGesture {
|
||||
self.selection = index
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(0)
|
||||
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
tabBar
|
||||
|
||||
tabViews[selection]
|
||||
.padding(0)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
.padding(0)
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ struct FilesView: View {
|
||||
@AppStorage("settings.interface.animationEnabled") private var animationEnabled: Bool = true
|
||||
@AppStorage("settings.general.confirmAlert") private var confirmAlert: Bool = false
|
||||
@AppStorage("settings.interface.details") private var detailsEnabled: Bool = true
|
||||
@AppStorage("settings.general.oneshot") private var oneShotMode: Bool = false
|
||||
@State private var showAlert = false
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@Binding var showPopover: Bool
|
||||
@@ -77,7 +78,7 @@ struct FilesView: View {
|
||||
showPopover = false
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: "Close"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: String(localized: "Close")))
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +121,7 @@ struct FilesView: View {
|
||||
}
|
||||
Spacer()
|
||||
|
||||
Button("\(detailsEnabled ? "Hide Details" : "Show Details")") {
|
||||
Button("\(detailsEnabled ? String(localized: "Hide Details") : String(localized: "Show Details"))") {
|
||||
withAnimation(Animation.easeInOut(duration: animationEnabled ? 0.35 : 0)) {
|
||||
detailsEnabled.toggle()
|
||||
}
|
||||
@@ -148,7 +149,7 @@ struct FilesView: View {
|
||||
VStack(alignment: .trailing, spacing: 5) {
|
||||
Text("\(displaySizeTotal)").font(.callout).fontWeight(.bold)//.help("Total size on disk")
|
||||
|
||||
Text("\(appState.appInfo.fileSize.count == 1 ? "\(appState.selectedItems.count) of \(appState.appInfo.fileSize.count) item" : "\(appState.selectedItems.count) of \(appState.appInfo.fileSize.count) items")")
|
||||
Text("\(appState.appInfo.fileSize.count == 1 ? "\(appState.selectedItems.count) \(String(localized: "of")) \(appState.appInfo.fileSize.count) \(String(localized: "item"))" : "\(appState.selectedItems.count) \(String(localized: "of")) \(appState.appInfo.fileSize.count) \(String(localized: "items"))")")
|
||||
.font(.footnote)
|
||||
|
||||
if let creationDate = appState.appInfo.creationDate {
|
||||
@@ -274,7 +275,7 @@ struct FilesView: View {
|
||||
Button("") {
|
||||
selectedSortAlpha.toggle()
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "line.3.horizontal.decrease.circle", label: selectedSortAlpha ? "Name" : "Size", help: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size", size: 16))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "line.3.horizontal.decrease.circle", label: String(localized: selectedSortAlpha ? "Name" : "Size"), help: String(localized: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size"), size: 16))
|
||||
|
||||
}
|
||||
.padding()
|
||||
@@ -341,7 +342,7 @@ struct FilesView: View {
|
||||
|
||||
|
||||
Button("\(sizeType == "Logical" ? totalSelectedSize.logical : totalSelectedSize.real)") {
|
||||
showCustomAlert(enabled: confirmAlert, title: "Warning", message: "Are you sure you want to remove these files?", style: .warning, onOk: {
|
||||
showCustomAlert(enabled: confirmAlert, title: String(localized: "Warning"), message: String(localized: "Are you sure you want to remove these files?"), style: .warning, onOk: {
|
||||
Task {
|
||||
|
||||
let selectedItemsArray = Array(appState.selectedItems)
|
||||
@@ -389,7 +390,7 @@ struct FilesView: View {
|
||||
// Match found, remove the app
|
||||
removeApp(appState: appState, withPath: appState.appInfo.path)
|
||||
|
||||
if appState.oneShotMode {
|
||||
if oneShotMode {
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
|
||||
@@ -408,7 +409,7 @@ struct FilesView: View {
|
||||
// Update the selectedFiles to remove references that are no longer present
|
||||
appState.selectedItems.removeAll()
|
||||
appState.sentinelMode = false
|
||||
if appState.oneShotMode {
|
||||
if oneShotMode {
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
}
|
||||
@@ -449,8 +450,7 @@ struct FilesView: View {
|
||||
warning = true
|
||||
showAlert = false
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", label: "Close", help: "Dismiss"))
|
||||
// Spacer()
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", label: String(localized: "Close"), help: String(localized: "Dismiss")))// Spacer()
|
||||
}
|
||||
.padding(15)
|
||||
.frame(width: 400, height: 250)
|
||||
@@ -526,8 +526,7 @@ struct FileDetailsItem: View {
|
||||
}
|
||||
|
||||
if isNested(path: path) {
|
||||
InfoButton(text: "Application file is nested within subdirectories. To prevent deleting incorrect folders, Pearcleaner will leave these alone. You may manually delete the remaining folders if required.")
|
||||
}
|
||||
InfoButton(text: String(localized: "Application file is nested within subdirectories. To prevent deleting incorrect folders, Pearcleaner will leave these alone. You may manually delete the remaining folders if required.")) }
|
||||
|
||||
if let imageView = folderImages(for: path.path) {
|
||||
imageView
|
||||
|
||||
@@ -161,10 +161,3 @@ struct MiniAppView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ struct ZombieView: View {
|
||||
showPopover = false
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: "Close"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: String(localized: "Close")))
|
||||
}
|
||||
}
|
||||
.padding(.top, (mini || menubarEnabled) ? 6 : 30)
|
||||
@@ -112,7 +112,7 @@ struct ZombieView: View {
|
||||
VStack(alignment: .trailing, spacing: 5) {
|
||||
Text("\(displaySizeTotal)").font(.callout).fontWeight(.bold)//.help("Total size on disk")
|
||||
|
||||
Text("\(selectedZombieItemsLocal.count) of \(searchZ.isEmpty ? appState.zombieFile.fileSize.count : memoizedFiles.count) \(appState.zombieFile.fileSize.count == 1 ? "item" : "items")")
|
||||
Text("\(selectedZombieItemsLocal.count) \(String(localized: "of")) \(searchZ.isEmpty ? appState.zombieFile.fileSize.count : memoizedFiles.count) \(appState.zombieFile.fileSize.count == 1 ? "\(String(localized: "item"))" : "\(String(localized: "items"))")")
|
||||
.font(.footnote).foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ struct ZombieView: View {
|
||||
selectedSortAlpha.toggle()
|
||||
updateMemoizedFiles(for: searchZ, sizeType: sizeType, selectedSortAlpha: selectedSortAlpha, force: true)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "line.3.horizontal.decrease.circle", label: selectedSortAlpha ? "Name" : "Size", help: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size", size: 16))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "line.3.horizontal.decrease.circle", label: String(localized: selectedSortAlpha ? "Name" : "Size"), help: String(localized: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size"), size: 16))
|
||||
|
||||
|
||||
}
|
||||
@@ -219,7 +219,7 @@ struct ZombieView: View {
|
||||
.buttonStyle(RescanButton())
|
||||
|
||||
Button("\(sizeType == "Logical" ? totalLogicalSizeUninstallBtn : totalRealSizeUninstallBtn)") {
|
||||
showCustomAlert(enabled: confirmAlert, title: "Warning", message: "Are you sure you want to remove these files?", style: .warning, onOk: {
|
||||
showCustomAlert(enabled: confirmAlert, title: String(localized: "Warning"), message: String(localized: "Are you sure you want to remove these files?"), style: .warning, onOk: {
|
||||
Task {
|
||||
|
||||
let selectedItemsArray = Array(selectedZombieItemsLocal)
|
||||
@@ -284,14 +284,14 @@ struct ZombieView: View {
|
||||
.font(.headline)
|
||||
Divider()
|
||||
Spacer()
|
||||
Text("Leftover file search is not 100% accurate as it doesn't have any uninstalled app bundles to check against for file exclusion. This does a best guess search for files/folders and excludes the ones that have overlap with your currently installed applications. Please confirm files marked for deletion really do belong to uninstalled applications.")
|
||||
Text("Orphaned file search is not 100% accurate as it doesn't have any uninstalled app bundles to check against for file exclusion. This does a best guess search for files/folders and excludes the ones that have overlap with your currently installed applications. Please confirm files marked for deletion really do belong to uninstalled applications.")
|
||||
.font(.subheadline)
|
||||
Spacer()
|
||||
Button("Close") {
|
||||
warning = true
|
||||
showAlert = false
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", label: "Close", help: "Dismiss"))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", label: String(localized: "Close"), help: String(localized: "Dismiss")))
|
||||
Spacer()
|
||||
}
|
||||
.padding(15)
|
||||
|
||||
Reference in New Issue
Block a user