mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 04:58:56 +00:00
v3.5.4
This commit is contained in:
@@ -521,10 +521,12 @@
|
|||||||
C72893142AFD51EA00C8C1CD /* Debug */ = {
|
C72893142AFD51EA00C8C1CD /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
APP_BUILD = "$(APP_BUILD)";
|
||||||
|
APP_VERSION = "$(APP_VERSION)";
|
||||||
CODE_SIGN_ENTITLEMENTS = PearcleanerSentinel/PearcleanerSentinel.entitlements;
|
CODE_SIGN_ENTITLEMENTS = PearcleanerSentinel/PearcleanerSentinel.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "";
|
CURRENT_PROJECT_VERSION = "$(APP_BUILD)";
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_TEAM = BK8443AXLU;
|
DEVELOPMENT_TEAM = BK8443AXLU;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@@ -540,10 +542,12 @@
|
|||||||
C72893152AFD51EA00C8C1CD /* Release */ = {
|
C72893152AFD51EA00C8C1CD /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
APP_BUILD = "$(APP_BUILD)";
|
||||||
|
APP_VERSION = "$(APP_VERSION)";
|
||||||
CODE_SIGN_ENTITLEMENTS = PearcleanerSentinel/PearcleanerSentinel.entitlements;
|
CODE_SIGN_ENTITLEMENTS = PearcleanerSentinel/PearcleanerSentinel.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "";
|
CURRENT_PROJECT_VERSION = "$(APP_BUILD)";
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_TEAM = BK8443AXLU;
|
DEVELOPMENT_TEAM = BK8443AXLU;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@@ -560,8 +564,8 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
APP_BUILD = 36;
|
APP_BUILD = 38;
|
||||||
APP_VERSION = 3.5.2;
|
APP_VERSION = 3.5.4;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@@ -593,7 +597,7 @@
|
|||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "";
|
CODE_SIGN_ENTITLEMENTS = "";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 33;
|
CURRENT_PROJECT_VERSION = "$(APP_BUILD)";
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
@@ -616,7 +620,7 @@
|
|||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = 3.4.2;
|
MARKETING_VERSION = "$(APP_VERSION)";
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
@@ -630,8 +634,8 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
APP_BUILD = 36;
|
APP_BUILD = 38;
|
||||||
APP_VERSION = 3.5.2;
|
APP_VERSION = 3.5.4;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@@ -663,7 +667,7 @@
|
|||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "";
|
CODE_SIGN_ENTITLEMENTS = "";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 33;
|
CURRENT_PROJECT_VERSION = "$(APP_BUILD)";
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
@@ -680,7 +684,7 @@
|
|||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = 3.4.2;
|
MARKETING_VERSION = "$(APP_VERSION)";
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
@@ -692,15 +696,14 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
APP_BUILD = 36;
|
APP_BUILD = "$(APP_BUILD)";
|
||||||
APP_VERSION = 3.5.2;
|
APP_VERSION = "$(APP_VERSION)";
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = Pearcleaner/Resources/Pearcleaner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Pearcleaner/Resources/Pearcleaner.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(APP_BUILD)";
|
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BK8443AXLU;
|
DEVELOPMENT_TEAM = BK8443AXLU;
|
||||||
@@ -718,7 +721,6 @@
|
|||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = "$(APP_VERSION)";
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
|
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
@@ -730,15 +732,14 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
APP_BUILD = 36;
|
APP_BUILD = "$(APP_BUILD)";
|
||||||
APP_VERSION = 3.5.2;
|
APP_VERSION = "$(APP_VERSION)";
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = Pearcleaner/Resources/Pearcleaner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Pearcleaner/Resources/Pearcleaner.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(APP_BUILD)";
|
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BK8443AXLU;
|
DEVELOPMENT_TEAM = BK8443AXLU;
|
||||||
@@ -756,7 +757,6 @@
|
|||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = "$(APP_VERSION)";
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
|
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
@@ -767,6 +767,8 @@
|
|||||||
C781216D2BC892A000BE06BD /* Debug */ = {
|
C781216D2BC892A000BE06BD /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
APP_BUILD = "$(APP_BUILD)";
|
||||||
|
APP_VERSION = "$(APP_VERSION)";
|
||||||
CODE_SIGN_ENTITLEMENTS = FinderOpen/FinderOpen.entitlements;
|
CODE_SIGN_ENTITLEMENTS = FinderOpen/FinderOpen.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
@@ -797,6 +799,8 @@
|
|||||||
C781216E2BC892A000BE06BD /* Release */ = {
|
C781216E2BC892A000BE06BD /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
APP_BUILD = "$(APP_BUILD)";
|
||||||
|
APP_VERSION = "$(APP_VERSION)";
|
||||||
CODE_SIGN_ENTITLEMENTS = FinderOpen/FinderOpen.entitlements;
|
CODE_SIGN_ENTITLEMENTS = FinderOpen/FinderOpen.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ class AppPathFinder {
|
|||||||
|
|
||||||
|
|
||||||
private func getAllContainers(bundleURL: URL) -> [URL] {
|
private func getAllContainers(bundleURL: URL) -> [URL] {
|
||||||
var containers = [URL]()
|
var containers: [URL] = []
|
||||||
|
|
||||||
// Extract bundle identifier from bundleURL
|
// Extract bundle identifier from bundleURL
|
||||||
let bundleIdentifier = Bundle(url: bundleURL)?.bundleIdentifier
|
let bundleIdentifier = Bundle(url: bundleURL)?.bundleIdentifier
|
||||||
@@ -190,7 +190,9 @@ class AppPathFinder {
|
|||||||
|
|
||||||
// Get the regular container URL for the extracted bundle identifier
|
// Get the regular container URL for the extracted bundle identifier
|
||||||
if let groupContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: containerBundleIdentifier) {
|
if let groupContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: containerBundleIdentifier) {
|
||||||
containers.append(groupContainer)
|
if FileManager.default.fileExists(atPath: groupContainer.path) {
|
||||||
|
containers.append(groupContainer)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
printOS("Get Containers: Failed to retrieve container URL for bundle identifier: \(containerBundleIdentifier)")
|
printOS("Get Containers: Failed to retrieve container URL for bundle identifier: \(containerBundleIdentifier)")
|
||||||
}
|
}
|
||||||
@@ -221,23 +223,6 @@ class AppPathFinder {
|
|||||||
printOS("Error accessing the Containers directory: \(error)")
|
printOS("Error accessing the Containers directory: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// let fileURL = URL(fileURLWithPath: "/Users/alin/Library/Containers/2792352D-95FE-43AE-947D-FF4BF31DE4E6")
|
|
||||||
//
|
|
||||||
// do {
|
|
||||||
// // Retrieve the localized name
|
|
||||||
// let resourceValues = try fileURL.resourceValues(forKeys: [.localizedNameKey])
|
|
||||||
// if let localizedName = resourceValues.localizedName {
|
|
||||||
// print("Localized Name: \(localizedName)")
|
|
||||||
// } else {
|
|
||||||
// print("Localized name not available.")
|
|
||||||
// }
|
|
||||||
// } catch {
|
|
||||||
// print("Error retrieving localized name: \(error)")
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Return all found containers
|
// Return all found containers
|
||||||
return containers
|
return containers
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class AppState: ObservableObject
|
|||||||
@Published var currentView = CurrentDetailsView.empty
|
@Published var currentView = CurrentDetailsView.empty
|
||||||
@Published var showAlert: Bool = false
|
@Published var showAlert: Bool = false
|
||||||
@Published var sidebar: Bool = true
|
@Published var sidebar: Bool = true
|
||||||
@Published var isReminderVisible: Bool = false
|
// @Published var isReminderVisible: Bool = false
|
||||||
@Published var releases = [Release]()
|
@Published var releases = [Release]()
|
||||||
@Published var progressBar: (String, Double) = ("Ready", 0.0)
|
@Published var progressBar: (String, Double) = ("Ready", 0.0)
|
||||||
@Published var reload: Bool = false
|
@Published var reload: Bool = false
|
||||||
@@ -55,6 +55,7 @@ class AppState: ObservableObject
|
|||||||
fileSizeLogical: [:],
|
fileSizeLogical: [:],
|
||||||
fileIcon: [:]
|
fileIcon: [:]
|
||||||
)
|
)
|
||||||
|
|
||||||
updateExtensionStatus()
|
updateExtensionStatus()
|
||||||
NotificationCenter.default.addObserver(
|
NotificationCenter.default.addObserver(
|
||||||
self,
|
self,
|
||||||
@@ -66,9 +67,9 @@ class AppState: ObservableObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateExtensionStatus() {
|
@objc func updateExtensionStatus() {
|
||||||
let extentionStatus = FIFinderSyncController.isExtensionEnabled
|
let extensionStatus = FIFinderSyncController.isExtensionEnabled
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.finderExtensionEnabled = extentionStatus
|
self.finderExtensionEnabled = extensionStatus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,80 @@ struct SimpleButtonStyle: ButtonStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct RegularButtonStyle: ButtonStyle {
|
||||||
|
let icon: String
|
||||||
|
let label: String
|
||||||
|
let help: String
|
||||||
|
@State private var hovered = false
|
||||||
|
|
||||||
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
|
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
Image(systemName: icon).foregroundColor(Color("mode")).padding(.leading, 2).padding(.trailing, 0)
|
||||||
|
Text(label).textCase(.uppercase).foregroundColor(Color("mode")).fontWeight(.bold).padding(.trailing, 2)
|
||||||
|
|
||||||
|
}
|
||||||
|
.padding(8)
|
||||||
|
.background(!configuration.isPressed ? hovered ? Color("mode").opacity(0.4) : Color("mode").opacity(0) : Color("mode").opacity(0.5))
|
||||||
|
.cornerRadius(6)
|
||||||
|
.scaleEffect(configuration.isPressed ? 0.95 : 1)
|
||||||
|
.animation(.easeOut(duration: 0.2), value: configuration.isPressed)
|
||||||
|
.onHover { hovering in
|
||||||
|
withAnimation(Animation.easeIn(duration: 0.15)) {
|
||||||
|
hovered = hovering
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 6)
|
||||||
|
.strokeBorder(Color("mode").opacity(0.5), lineWidth: 1)
|
||||||
|
.scaleEffect(configuration.isPressed ? 0.95 : 1)
|
||||||
|
)
|
||||||
|
.help(help)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ResetSettingsButtonStyle: ButtonStyle {
|
||||||
|
@Binding var isResetting: Bool
|
||||||
|
let label: String
|
||||||
|
let help: String
|
||||||
|
@State private var hovered = false
|
||||||
|
|
||||||
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
if isResetting {
|
||||||
|
ProgressView()
|
||||||
|
.progressViewStyle(CircularProgressViewStyle())
|
||||||
|
.controlSize(.small)
|
||||||
|
.frame(width: 15)
|
||||||
|
} else {
|
||||||
|
Image(systemName: "gear")
|
||||||
|
.foregroundColor(Color("mode")).padding(.leading, 2).padding(.trailing, 0)
|
||||||
|
}
|
||||||
|
Text(label)
|
||||||
|
.textCase(.uppercase).foregroundColor(Color("mode")).fontWeight(.bold).padding(.trailing, 2)
|
||||||
|
}
|
||||||
|
.padding(8)
|
||||||
|
.background(!configuration.isPressed ? hovered ? Color("mode").opacity(0.4) : Color("mode").opacity(0) : Color("mode").opacity(0.5))
|
||||||
|
.cornerRadius(6)
|
||||||
|
.scaleEffect(configuration.isPressed ? 0.95 : 1)
|
||||||
|
.animation(.easeOut(duration: 0.2), value: configuration.isPressed)
|
||||||
|
.onHover { hovering in
|
||||||
|
withAnimation(Animation.easeIn(duration: 0.15)) {
|
||||||
|
hovered = hovering
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 6)
|
||||||
|
.strokeBorder(Color("mode").opacity(0.5), lineWidth: 1)
|
||||||
|
.scaleEffect(configuration.isPressed ? 0.95 : 1)
|
||||||
|
)
|
||||||
|
.help(help)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct InfoButton: View {
|
struct InfoButton: View {
|
||||||
@State private var isPopoverPresented: Bool = false
|
@State private var isPopoverPresented: Bool = false
|
||||||
@@ -769,7 +843,6 @@ func backgroundView(themeSettings: ThemeSettings, darker: Bool = false, glass: B
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct PresetColor: ButtonStyle {
|
struct PresetColor: ButtonStyle {
|
||||||
var fillColor: Color
|
var fillColor: Color
|
||||||
var label: String
|
var label: String
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ class ThemeSettings: ObservableObject {
|
|||||||
|
|
||||||
// light - Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
|
// light - Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
|
||||||
// dark - Color(.sRGB, red: 0.149, green: 0.149, blue: 0.149, opacity: 1)
|
// dark - Color(.sRGB, red: 0.149, green: 0.149, blue: 0.149, opacity: 1)
|
||||||
|
// slate - Color(.sRGB, red: 0.188143, green: 0.208556, blue: 0.262679, opacity: 1)
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// Initialize color from UserDefaults or use a default value
|
// Initialize color from UserDefaults or use a default value
|
||||||
if let components = UserDefaults.standard.object(forKey: colorKey) as? [CGFloat], components.count >= 4 {
|
if let components = UserDefaults.standard.object(forKey: colorKey) as? [CGFloat], components.count >= 4 {
|
||||||
themeColor = Color(.sRGB, red: components[0], green: components[1], blue: components[2], opacity: components[3])
|
themeColor = Color(.sRGB, red: components[0], green: components[1], blue: components[2], opacity: components[3])
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
themeColor = Color.clear
|
themeColor = Color.clear
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,8 @@ class ThemeSettings: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func resetToDefault(dark: Bool = true) {
|
func resetToDefault(dark: Bool = true) {
|
||||||
themeColor = dark ? Color(.sRGB, red: 0.149, green: 0.149, blue: 0.149, opacity: 1) : Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
|
themeColor = dark ? Color(.sRGB, red: 0.188143, green: 0.208556, blue: 0.262679, opacity: 1) : Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
|
||||||
|
// themeColor = dark ? Color(.sRGB, red: 0.149, green: 0.149, blue: 0.149, opacity: 1) : Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
|
||||||
saveThemeColor()
|
saveThemeColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ class ThemeSettings: ObservableObject {
|
|||||||
let slate = colorScheme.colorScheme == .light ? Color(.sRGB, red: 0.499549, green: 0.545169, blue: 0.682028, opacity: 1) : Color(.sRGB, red: 0.188143, green: 0.208556, blue: 0.262679, opacity: 1)
|
let slate = colorScheme.colorScheme == .light ? Color(.sRGB, red: 0.499549, green: 0.545169, blue: 0.682028, opacity: 1) : Color(.sRGB, red: 0.188143, green: 0.208556, blue: 0.262679, opacity: 1)
|
||||||
let solarized = colorScheme.colorScheme == .light ? Color(.sRGB, red: 0.554372, green: 0.6557, blue: 0.734336, opacity: 1) : Color(.sRGB, red: 0.117257, green: 0.22506, blue: 0.249171, opacity: 1)
|
let solarized = colorScheme.colorScheme == .light ? Color(.sRGB, red: 0.554372, green: 0.6557, blue: 0.734336, opacity: 1) : Color(.sRGB, red: 0.117257, green: 0.22506, blue: 0.249171, opacity: 1)
|
||||||
let dracula = colorScheme.colorScheme == .light ? Color(.sRGB, red: 0.567094, green: 0.562125, blue: 0.81285, opacity: 1) : Color(.sRGB, red: 0.268614, green: 0.264737, blue: 0.383503, opacity: 1)
|
let dracula = colorScheme.colorScheme == .light ? Color(.sRGB, red: 0.567094, green: 0.562125, blue: 0.81285, opacity: 1) : Color(.sRGB, red: 0.268614, green: 0.264737, blue: 0.383503, opacity: 1)
|
||||||
|
let macOS = colorScheme.colorScheme == .light ? Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1) : Color(.sRGB, red: 0.149, green: 0.149, blue: 0.149, opacity: 1)
|
||||||
|
|
||||||
switch preset {
|
switch preset {
|
||||||
case "slate":
|
case "slate":
|
||||||
@@ -63,6 +65,8 @@ class ThemeSettings: ObservableObject {
|
|||||||
return solarized
|
return solarized
|
||||||
case "dracula":
|
case "dracula":
|
||||||
return dracula
|
return dracula
|
||||||
|
case "macOS":
|
||||||
|
return macOS
|
||||||
default:
|
default:
|
||||||
return themeColor
|
return themeColor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,17 +312,14 @@ func convertICNSToPNG(icon: NSImage, size: NSSize) -> NSImage? {
|
|||||||
|
|
||||||
// Get icon for files and folders
|
// Get icon for files and folders
|
||||||
func getIconForFileOrFolder(atPath path: URL) -> Image? {
|
func getIconForFileOrFolder(atPath path: URL) -> Image? {
|
||||||
let icon = NSWorkspace.shared.icon(forFile: path.path)
|
return Image(nsImage: NSWorkspace.shared.icon(forFile: path.path))
|
||||||
let nsImage = icon
|
|
||||||
return Image(nsImage: nsImage)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIconForFileOrFolderNS(atPath path: URL) -> NSImage? {
|
func getIconForFileOrFolderNS(atPath path: URL) -> NSImage? {
|
||||||
let icon = NSWorkspace.shared.icon(forFile: path.path)
|
return NSWorkspace.shared.icon(forFile: path.path)
|
||||||
let nsImage = icon
|
|
||||||
return nsImage
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get average color from image
|
// Get average color from image
|
||||||
extension NSImage {
|
extension NSImage {
|
||||||
var averageColor: NSColor? {
|
var averageColor: NSColor? {
|
||||||
@@ -393,6 +390,60 @@ func removeApp(appState: AppState, withId id: UUID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check if file/folder name has localized variant
|
||||||
|
func showLocalized(url: URL) -> String {
|
||||||
|
guard FileManager.default.fileExists(atPath: url.path) else {
|
||||||
|
return url.lastPathComponent
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
// Retrieve the localized name
|
||||||
|
let resourceValues = try url.resourceValues(forKeys: [.localizedNameKey])
|
||||||
|
if let localizedName = resourceValues.localizedName {
|
||||||
|
return localizedName
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
printOS("Error retrieving localized name: \(error)")
|
||||||
|
}
|
||||||
|
// Return the last path component as a fallback
|
||||||
|
return url.lastPathComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return image for different folders
|
||||||
|
func folderImages(for path: String) -> AnyView? {
|
||||||
|
if path.contains("/Library/Containers/") || path.contains("/Library/Group Containers/") {
|
||||||
|
return AnyView(
|
||||||
|
Image(systemName: "shippingbox.fill")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 13)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
.help("Container")
|
||||||
|
)
|
||||||
|
} else if path.contains("/Library/Application Scripts/") {
|
||||||
|
return AnyView(
|
||||||
|
Image(systemName: "applescript.fill")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 13)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
.help("Application Script")
|
||||||
|
)
|
||||||
|
} else if path.contains(".plist") {
|
||||||
|
return AnyView(
|
||||||
|
Image(systemName: "doc.badge.gearshape.fill")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 13)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
.help("Plist File")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return nil if no conditions are met
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check if app bundle is nested
|
// Check if app bundle is nested
|
||||||
func isNested(path: URL) -> Bool {
|
func isNested(path: URL) -> Bool {
|
||||||
let applicationsPath = "/Applications"
|
let applicationsPath = "/Applications"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import AppKit
|
import AppKit
|
||||||
import ServiceManagement
|
//import ServiceManagement
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct PearcleanerApp: App {
|
struct PearcleanerApp: App {
|
||||||
@@ -221,7 +221,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
|
|||||||
|
|
||||||
UserDefaults.standard.set(displayMode?.rawValue, forKey: "displayMode")
|
UserDefaults.standard.set(displayMode?.rawValue, forKey: "displayMode")
|
||||||
|
|
||||||
ThemeSettings.shared.themeColor = isDarkMode() ? Color(.sRGB, red: 0.149, green: 0.149, blue: 0.149, opacity: 1) : Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
|
// Customize dark mode color to use Slate by default
|
||||||
|
ThemeSettings.shared.themeColor = isDarkMode() ? Color(.sRGB, red: 0.188143, green: 0.208556, blue: 0.262679, opacity: 1) : Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
|
||||||
|
// ThemeSettings.shared.themeColor = isDarkMode() ? Color(.sRGB, red: 0.149, green: 0.149, blue: 0.149, opacity: 1) : Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
|
||||||
ThemeSettings.shared.saveThemeColor()
|
ThemeSettings.shared.saveThemeColor()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import ServiceManagement
|
//import ServiceManagement
|
||||||
import FinderSync
|
import FinderSync
|
||||||
|
|
||||||
struct GeneralSettingsTab: View {
|
struct GeneralSettingsTab: View {
|
||||||
@@ -29,8 +29,8 @@ struct GeneralSettingsTab: View {
|
|||||||
@State private var accessStatus: Bool = false
|
@State private var accessStatus: Bool = false
|
||||||
@Binding var showPopover: Bool
|
@Binding var showPopover: Bool
|
||||||
@Binding var search: String
|
@Binding var search: String
|
||||||
|
|
||||||
@State var selectedIndex: Int?
|
@State var selectedIndex: Int?
|
||||||
|
@State private var isResetting = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Form {
|
Form {
|
||||||
@@ -290,6 +290,7 @@ struct GeneralSettingsTab: View {
|
|||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.padding(.trailing)
|
.padding(.trailing)
|
||||||
.foregroundStyle(appState.finderExtensionEnabled ? .green : .red)
|
.foregroundStyle(appState.finderExtensionEnabled ? .green : .red)
|
||||||
|
.saturation(displayMode.colorScheme == .dark ? 0.5 : 1)
|
||||||
Text(appState.finderExtensionEnabled ? "Context menu extension for Finder is enabled" : "Context menu extension for Finder is disabled")
|
Text(appState.finderExtensionEnabled ? "Context menu extension for Finder is enabled" : "Context menu extension for Finder is disabled")
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
@@ -307,7 +308,20 @@ struct GeneralSettingsTab: View {
|
|||||||
.padding(5)
|
.padding(5)
|
||||||
.padding(.leading)
|
.padding(.leading)
|
||||||
|
|
||||||
|
// === Reset Settings =============================================================================================
|
||||||
|
|
||||||
|
HStack() {
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Button("") {
|
||||||
|
resetUserDefaults()
|
||||||
|
}
|
||||||
|
.buttonStyle(ResetSettingsButtonStyle(isResetting: $isResetting, label: "Reset Settings", help: "Reset all app settings to default"))
|
||||||
|
.disabled(isResetting)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(.vertical, 5)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -324,8 +338,28 @@ struct GeneralSettingsTab: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.frame(width: 500, height: 570)
|
.frame(width: 500, height: 620)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var keysToIgnore: Set<String> {
|
||||||
|
["windowWidthKey", "windowHeightKey", "windowWidthKeyMini", "windowHeightKeyMini", "windowXKey", "windowYKey"]
|
||||||
|
}
|
||||||
|
|
||||||
|
private func resetUserDefaults() {
|
||||||
|
isResetting = true
|
||||||
|
DispatchQueue.global(qos: .background).async {
|
||||||
|
let defaults = UserDefaults.standard
|
||||||
|
let dictionary = defaults.dictionaryRepresentation()
|
||||||
|
dictionary.keys.forEach { key in
|
||||||
|
if !keysToIgnore.contains(key) {
|
||||||
|
defaults.removeObject(forKey: key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
isResetting = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,11 @@ struct InterfaceSettingsTab: View {
|
|||||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||||
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
|
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
|
||||||
@AppStorage("settings.general.glass") private var glass: Bool = true
|
@AppStorage("settings.general.glass") private var glass: Bool = false
|
||||||
@AppStorage("settings.general.dark") var isDark: Bool = true
|
@AppStorage("settings.general.dark") var isDark: Bool = true
|
||||||
@AppStorage("settings.general.popover") private var popoverStay: Bool = true
|
@AppStorage("settings.general.popover") private var popoverStay: Bool = true
|
||||||
@AppStorage("settings.general.miniview") private var miniView: Bool = true
|
@AppStorage("settings.general.miniview") private var miniView: Bool = true
|
||||||
|
@AppStorage("settings.general.animateLogo") private var animateLogo: Bool = true
|
||||||
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
|
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
|
||||||
@AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "pear-4"
|
@AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "pear-4"
|
||||||
@State private var isLaunchAtLoginEnabled: Bool = false
|
@State private var isLaunchAtLoginEnabled: Bool = false
|
||||||
@@ -32,6 +33,14 @@ struct InterfaceSettingsTab: View {
|
|||||||
@Binding var search: String
|
@Binding var search: String
|
||||||
let icons = ["externaldrive", "trash", "folder", "pear-1", "pear-1.5", "pear-2", "pear-3", "pear-4"]
|
let icons = ["externaldrive", "trash", "folder", "pear-1", "pear-1.5", "pear-2", "pear-3", "pear-4"]
|
||||||
|
|
||||||
|
var isMacOS14OrHigher: Bool {
|
||||||
|
if #available(macOS 14, *) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|
||||||
Form {
|
Form {
|
||||||
@@ -67,6 +76,38 @@ struct InterfaceSettingsTab: View {
|
|||||||
.padding(.leading)
|
.padding(.leading)
|
||||||
|
|
||||||
|
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
Image(systemName: animateLogo ? "play.fill" : "pause")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
.padding(.trailing)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
VStack(alignment: .leading, spacing: 5) {
|
||||||
|
Text("\(animateLogo ? "Logo animation enabled" : "Logo animation disabled")")
|
||||||
|
.font(.callout)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
|
||||||
|
}
|
||||||
|
if !isMacOS14OrHigher {
|
||||||
|
Text("(macOS 14+)")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.3))
|
||||||
|
.padding(.leading, 5)
|
||||||
|
}
|
||||||
|
// InfoButton(text: "The logo animation is only available in macOS 14 or higher", color: nil, label: "")
|
||||||
|
Spacer()
|
||||||
|
Toggle(isOn: $animateLogo, label: {
|
||||||
|
})
|
||||||
|
.toggleStyle(.switch)
|
||||||
|
.disabled(!isMacOS14OrHigher)
|
||||||
|
}
|
||||||
|
.padding(5)
|
||||||
|
.padding(.leading)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
Image(systemName: "paintbrush")
|
Image(systemName: "paintbrush")
|
||||||
.resizable()
|
.resizable()
|
||||||
@@ -82,22 +123,33 @@ struct InterfaceSettingsTab: View {
|
|||||||
InfoButton(text: "When using a custom color, you might need to change the application color mode below to Dark or Light so text is readable", color: nil, label: "")
|
InfoButton(text: "When using a custom color, you might need to change the application color mode below to Dark or Light so text is readable", color: nil, label: "")
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button("") {
|
|
||||||
themeSettings.setPreset(preset: "slate", colorScheme: displayMode)
|
|
||||||
}
|
|
||||||
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "slate", colorScheme: displayMode), label: "Slate"))
|
|
||||||
|
|
||||||
Button("") {
|
HStack(spacing: 10) {
|
||||||
themeSettings.setPreset(preset: "dracula", colorScheme: displayMode)
|
Button("") {
|
||||||
}
|
themeSettings.setPreset(preset: "slate", colorScheme: displayMode)
|
||||||
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "dracula", colorScheme: displayMode), label: "Dracula"))
|
}
|
||||||
.padding(.horizontal)
|
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "slate", colorScheme: displayMode), label: "Slate"))
|
||||||
|
|
||||||
Button("") {
|
Button("") {
|
||||||
themeSettings.setPreset(preset: "solarized", colorScheme: displayMode)
|
themeSettings.setPreset(preset: "dracula", colorScheme: displayMode)
|
||||||
themeSettings.saveThemeColor()
|
}
|
||||||
|
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "dracula", colorScheme: displayMode), label: "Dracula"))
|
||||||
|
|
||||||
|
Button("") {
|
||||||
|
themeSettings.setPreset(preset: "solarized", colorScheme: displayMode)
|
||||||
|
themeSettings.saveThemeColor()
|
||||||
|
}
|
||||||
|
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "solarized", colorScheme: displayMode), label: "Solarized"))
|
||||||
|
|
||||||
|
Button("") {
|
||||||
|
themeSettings.setPreset(preset: "macOS", colorScheme: displayMode)
|
||||||
|
themeSettings.saveThemeColor()
|
||||||
|
}
|
||||||
|
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "macOS", colorScheme: displayMode), label: "macOS"))
|
||||||
}
|
}
|
||||||
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "solarized", colorScheme: displayMode), label: "Solarized"))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
@@ -106,6 +158,7 @@ struct InterfaceSettingsTab: View {
|
|||||||
themeSettings.saveThemeColor()
|
themeSettings.saveThemeColor()
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 5)
|
.padding(.horizontal, 5)
|
||||||
|
|
||||||
Button("") {
|
Button("") {
|
||||||
themeSettings.resetToDefault(dark: colorScheme == .dark)
|
themeSettings.resetToDefault(dark: colorScheme == .dark)
|
||||||
}
|
}
|
||||||
@@ -182,7 +235,6 @@ struct InterfaceSettingsTab: View {
|
|||||||
} else {
|
} else {
|
||||||
displayMode.colorScheme = .light
|
displayMode.colorScheme = .light
|
||||||
}
|
}
|
||||||
// displayMode.colorScheme = nil
|
|
||||||
themeSettings.resetToDefault(dark: isDarkMode())
|
themeSettings.resetToDefault(dark: isDarkMode())
|
||||||
// Refresh foreground colors
|
// Refresh foreground colors
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
@@ -193,7 +245,7 @@ struct InterfaceSettingsTab: View {
|
|||||||
}
|
}
|
||||||
case "Dark":
|
case "Dark":
|
||||||
displayMode.colorScheme = .dark
|
displayMode.colorScheme = .dark
|
||||||
// themeSettings.resetToDefault(dark: true)
|
themeSettings.resetToDefault(dark: true)
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
self.selectedTab = .interface
|
self.selectedTab = .interface
|
||||||
}
|
}
|
||||||
@@ -202,7 +254,7 @@ struct InterfaceSettingsTab: View {
|
|||||||
}
|
}
|
||||||
case "Light":
|
case "Light":
|
||||||
displayMode.colorScheme = .light
|
displayMode.colorScheme = .light
|
||||||
// themeSettings.resetToDefault(dark: false)
|
themeSettings.resetToDefault(dark: false)
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
self.selectedTab = .interface
|
self.selectedTab = .interface
|
||||||
}
|
}
|
||||||
@@ -506,7 +558,7 @@ struct InterfaceSettingsTab: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.frame(width: 500, height: 570)
|
.frame(width: 500, height: 600)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ struct SettingsView: View {
|
|||||||
@Binding var showPopover: Bool
|
@Binding var showPopover: Bool
|
||||||
@Binding var search: String
|
@Binding var search: String
|
||||||
@Binding var showFeature: Bool
|
@Binding var showFeature: Bool
|
||||||
@AppStorage("settings.general.glass") private var glass: Bool = true
|
@AppStorage("settings.general.glass") private var glass: Bool = false
|
||||||
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
|
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|||||||
@@ -18,47 +18,44 @@ struct AppListItems: View {
|
|||||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||||
@AppStorage("settings.general.miniview") private var miniView: Bool = true
|
@AppStorage("settings.general.miniview") private var miniView: Bool = true
|
||||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||||
|
@AppStorage("settings.general.glass") private var glass: Bool = true
|
||||||
|
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
|
||||||
@Binding var showPopover: Bool
|
@Binding var showPopover: Bool
|
||||||
@EnvironmentObject var locations: Locations
|
@EnvironmentObject var locations: Locations
|
||||||
let itemId = UUID()
|
let itemId = UUID()
|
||||||
let appInfo: AppInfo
|
let appInfo: AppInfo
|
||||||
var isSelected: Bool {
|
var isSelected: Bool {
|
||||||
appState.appInfo.path == appInfo.path
|
appState.appInfo.id == appInfo.id
|
||||||
}
|
}
|
||||||
@State private var hoveredItemPath: URL? = nil
|
@State private var hoveredItemPath: URL? = nil
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|
||||||
HStack(alignment: .center) {
|
ZStack() {
|
||||||
|
|
||||||
if (isHovered || isSelected) && mini {
|
HStack(alignment: .center) {
|
||||||
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 {
|
if let appIcon = appInfo.appIcon {
|
||||||
ZStack {
|
ZStack {
|
||||||
Image(nsImage: appIcon)
|
Image(nsImage: appIcon)
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
.frame(width: 30, height: 30)
|
.frame(width: (isHovered || isSelected) ? 32 : 30, height: (isHovered || isSelected) ? 32 : 30)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||||
.shadow(color: .black.opacity(0.5), radius: 2, y: 2)
|
// .shadow(color: Color("pop").opacity(0.8), radius: isSelected ? 2 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 5) {
|
VStack(alignment: .leading, spacing: 5) {
|
||||||
Text(appInfo.appName)
|
Text(appInfo.appName)
|
||||||
.font(.system(size: 12))
|
.font(.system(size: (isHovered || isSelected) ? 14 : 12))
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.truncationMode(.tail)
|
.truncationMode(.tail)
|
||||||
.padding(.horizontal, 5)
|
.padding(.horizontal, 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if appInfo.webApp {
|
if appInfo.webApp {
|
||||||
@@ -83,75 +80,58 @@ struct AppListItems: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text(appInfo.appVersion)
|
Text(appInfo.appVersion)
|
||||||
.font(.footnote)
|
.font(.system(size: (isHovered || isSelected) ? 12 : 10))
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
|
||||||
if (isHovered || isSelected) && !mini {
|
// if (isHovered || isSelected) {
|
||||||
Triangle()
|
// RoundedRectangle(cornerRadius: 50)
|
||||||
.fill(themeSettings.themeColor)
|
// .fill(isSelected ? Color("pear") : Color("mode").opacity(0.5))
|
||||||
.frame(width: isSelected ? 16 : 8, height: 30)
|
// .frame(width: isSelected ? 4 : 2, height: 25)
|
||||||
.padding(.leading, 5)
|
// .padding(.trailing, 5)
|
||||||
.offset(x: 22)
|
// }
|
||||||
.zIndex(5)
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.frame(height: 35)
|
||||||
|
.padding(.horizontal)
|
||||||
|
.padding(.vertical, 5)
|
||||||
|
.help(appInfo.appName)
|
||||||
|
.onHover { hovering in
|
||||||
|
withAnimation(Animation.easeIn(duration: 0.2)) {
|
||||||
|
self.isHovered = hovering
|
||||||
|
self.hoveredItemPath = isHovered ? appInfo.path : nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onTapGesture {
|
||||||
|
withAnimation(Animation.easeInOut(duration: 0.4)) {
|
||||||
|
if isSelected {
|
||||||
|
appState.appInfo = .empty
|
||||||
|
appState.selectedItems = []
|
||||||
|
appState.currentView = miniView ? .apps : .empty
|
||||||
|
showPopover = false
|
||||||
|
} else {
|
||||||
|
showAppInFiles(appInfo: appInfo, appState: appState, locations: locations, showPopover: $showPopover)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.background{
|
||||||
|
Rectangle()
|
||||||
|
.fill(isSelected && !glass ? themeSettings.themeColor : .clear)
|
||||||
|
}
|
||||||
|
.overlay{
|
||||||
|
if (isHovered || isSelected) {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
RoundedRectangle(cornerRadius: 50)
|
||||||
|
.fill(isSelected ? Color("pear") : Color("mode").opacity(0.5))
|
||||||
|
.frame(width: isSelected ? 4 : 2, height: 25)
|
||||||
|
.padding(.trailing, 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 5)
|
|
||||||
.help(appInfo.appName)
|
|
||||||
.onHover { hovering in
|
|
||||||
withAnimation(Animation.easeIn(duration: 0.2)) {
|
|
||||||
self.isHovered = hovering
|
|
||||||
self.hoveredItemPath = isHovered ? appInfo.path : nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onTapGesture {
|
|
||||||
withAnimation(Animation.easeInOut(duration: 0.4)) {
|
|
||||||
if isSelected {
|
|
||||||
appState.appInfo = .empty
|
|
||||||
appState.currentView = miniView ? .apps : .empty
|
|
||||||
showPopover = false
|
|
||||||
} else {
|
|
||||||
showAppInFiles(appInfo: appInfo, appState: appState, locations: locations, showPopover: $showPopover)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func opacityForItem(_ path: URL) -> Double {
|
|
||||||
// Check if any item is selected
|
|
||||||
let isAnyItemSelected = appState.sortedApps.contains(where: { $0.path == appState.appInfo.path })
|
|
||||||
|
|
||||||
let isItemSelected = appState.appInfo.path == path
|
|
||||||
let isItemHovered = hoveredItemPath == path
|
|
||||||
|
|
||||||
// Logic to determine grayscale level
|
|
||||||
if isItemSelected || !isAnyItemSelected || isItemHovered {
|
|
||||||
return 0 // No grayscale
|
|
||||||
} else {
|
|
||||||
return 1.0 // Full grayscale
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return isAnyItemSelected ? (appState.appInfo.path == appInfo.path ? 0 : 1.0) : 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct Triangle: Shape {
|
|
||||||
func path(in rect: CGRect) -> Path {
|
|
||||||
var path = Path()
|
|
||||||
|
|
||||||
// Start at the top right
|
|
||||||
path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
|
|
||||||
// Add line to the bottom right
|
|
||||||
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
|
|
||||||
// Add line to the left point
|
|
||||||
path.addLine(to: CGPoint(x: rect.minX, y: rect.midY))
|
|
||||||
// Close the path
|
|
||||||
path.closeSubpath()
|
|
||||||
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ struct AppsListView: View {
|
|||||||
SectionView(title: "System", count: filteredSystemApps.count, apps: filteredSystemApps, search: $search, showPopover: $showPopover)
|
SectionView(title: "System", count: filteredSystemApps.count, apps: filteredSystemApps, search: $search, showPopover: $showPopover)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
// .padding(.horizontal)
|
||||||
.padding(.top, !mini ? 4 : 0)
|
.padding(.top, !mini ? 4 : 0)
|
||||||
}
|
}
|
||||||
.scrollIndicators(.never)
|
.scrollIndicators(.never)
|
||||||
@@ -47,11 +47,11 @@ struct SectionView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
Header(title: title, count: count, showPopover: $showPopover)
|
Header(title: title, count: count, showPopover: $showPopover)
|
||||||
|
.padding(.leading, 5)
|
||||||
ForEach(apps, id: \.self) { appInfo in
|
ForEach(apps, id: \.self) { appInfo in
|
||||||
AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
|
AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
|
||||||
.padding(.vertical, 5)
|
|
||||||
if appInfo != apps.last {
|
if appInfo != apps.last {
|
||||||
Divider().padding(.horizontal, 5)
|
// Divider().padding(.horizontal, 5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,8 +110,6 @@ struct FilesView: View {
|
|||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 50, height: 50)
|
.frame(width: 50, height: 50)
|
||||||
// .clipShape(RoundedRectangle(cornerRadius: 8))
|
|
||||||
// .padding(.trailing)
|
|
||||||
.padding()
|
.padding()
|
||||||
.background{
|
.background{
|
||||||
RoundedRectangle(cornerRadius: 16)
|
RoundedRectangle(cornerRadius: 16)
|
||||||
@@ -288,15 +286,17 @@ struct FilesView: View {
|
|||||||
showPopover = false
|
showPopover = false
|
||||||
updateOnMain {
|
updateOnMain {
|
||||||
appState.currentView = mini ? .apps : .empty
|
appState.currentView = mini ? .apps : .empty
|
||||||
appState.isReminderVisible.toggle()
|
// appState.isReminderVisible.toggle()
|
||||||
}
|
}
|
||||||
if sentinel {
|
if sentinel {
|
||||||
launchctl(load: true)
|
launchctl(load: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove app from app list if main app bundle is removed
|
// Remove app from app list if main app bundle is removed for regular and wrapped apps
|
||||||
if selectedItemsArray.contains(where: { $0.absoluteString == appState.appInfo.path.absoluteString }) {
|
if (appState.appInfo.wrapped && selectedItemsArray.contains(where: { $0.absoluteString == appState.appInfo.path.deletingLastPathComponent().deletingLastPathComponent().absoluteString })) ||
|
||||||
|
(!appState.appInfo.wrapped && selectedItemsArray.contains(where: { $0.absoluteString == appState.appInfo.path.absoluteString })) {
|
||||||
|
// Match found, remove the app
|
||||||
removeApp(appState: appState, withId: appState.appInfo.id)
|
removeApp(appState: appState, withId: appState.appInfo.id)
|
||||||
} else {
|
} else {
|
||||||
// Add deleted appInfo object to trashed array
|
// Add deleted appInfo object to trashed array
|
||||||
@@ -373,16 +373,23 @@ struct FileDetailsItem: View {
|
|||||||
.shadow(color: Color("mode"), radius: isHovered ? 2 : 0)
|
.shadow(color: Color("mode"), radius: isHovered ? 2 : 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 5) {
|
VStack(alignment: .leading, spacing: 5) {
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
Text(path.lastPathComponent)
|
Text(showLocalized(url: path))
|
||||||
.font(.title3)
|
.font(.title3)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.truncationMode(.tail)
|
.truncationMode(.tail)
|
||||||
.help(path.lastPathComponent)
|
.help(path.lastPathComponent)
|
||||||
|
|
||||||
if isNested(path: path) {
|
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.", color: nil, label: "")
|
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.", color: nil, label: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let imageView = folderImages(for: path.path) {
|
||||||
|
imageView
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(path.path)
|
Text(path.path)
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ struct MenuBarMiniAppView: View {
|
|||||||
.padding(.leading, 10)
|
.padding(.leading, 10)
|
||||||
|
|
||||||
SearchBarMiniBottom(search: $search)
|
SearchBarMiniBottom(search: $search)
|
||||||
// .padding(.leading, 20)
|
|
||||||
|
|
||||||
Button("More") {
|
Button("More") {
|
||||||
self.showMenu.toggle()
|
self.showMenu.toggle()
|
||||||
@@ -105,26 +104,11 @@ struct MenuBarMiniAppView: View {
|
|||||||
.padding()
|
.padding()
|
||||||
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
|
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
|
||||||
|
|
||||||
// .background(
|
|
||||||
// Group {
|
|
||||||
// if glass {
|
|
||||||
// GlassEffect(material: .sidebar, blendingMode: .behindWindow)
|
|
||||||
// .edgesIgnoringSafeArea(.all)
|
|
||||||
// } else {
|
|
||||||
// Rectangle()
|
|
||||||
// .fill(Color("pop"))
|
|
||||||
// .padding(-80)
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// .padding(.horizontal)
|
.padding(.top, 5)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
@@ -137,20 +121,6 @@ struct MenuBarMiniAppView: View {
|
|||||||
.frame(minWidth: 300, minHeight: 370)
|
.frame(minWidth: 300, minHeight: 370)
|
||||||
.edgesIgnoringSafeArea(.all)
|
.edgesIgnoringSafeArea(.all)
|
||||||
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
|
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
|
||||||
|
|
||||||
// .background(
|
|
||||||
// Group {
|
|
||||||
// if glass {
|
|
||||||
// GlassEffect(material: .sidebar, blendingMode: .behindWindow)
|
|
||||||
// .edgesIgnoringSafeArea(.all)
|
|
||||||
// } else {
|
|
||||||
// Rectangle()
|
|
||||||
// .fill(Color("pop"))
|
|
||||||
// .padding(-80)
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
.transition(.opacity)
|
.transition(.opacity)
|
||||||
.popover(isPresented: $showPopover, arrowEdge: .leading) {
|
.popover(isPresented: $showPopover, arrowEdge: .leading) {
|
||||||
VStack {
|
VStack {
|
||||||
@@ -165,20 +135,6 @@ struct MenuBarMiniAppView: View {
|
|||||||
}
|
}
|
||||||
.interactiveDismissDisabled(popoverStay)
|
.interactiveDismissDisabled(popoverStay)
|
||||||
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
|
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
|
||||||
|
|
||||||
// .background(
|
|
||||||
// Group {
|
|
||||||
// if glass {
|
|
||||||
// GlassEffect(material: .sidebar, blendingMode: .behindWindow)
|
|
||||||
// .edgesIgnoringSafeArea(.all)
|
|
||||||
// } else {
|
|
||||||
// Rectangle()
|
|
||||||
// .fill(Color("pop"))
|
|
||||||
// .padding(-80)
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
.frame(width: 650, height: 500)
|
.frame(width: 650, height: 500)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ struct MiniEmptyView: View {
|
|||||||
@EnvironmentObject var locations: Locations
|
@EnvironmentObject var locations: Locations
|
||||||
@State private var animateGradient: Bool = false
|
@State private var animateGradient: Bool = false
|
||||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||||
|
@AppStorage("settings.general.animateLogo") private var animateLogo: Bool = true
|
||||||
@Binding var showPopover: Bool
|
@Binding var showPopover: Bool
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -100,18 +101,52 @@ struct MiniEmptyView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
|
if #available(macOS 14, *) {
|
||||||
.mask(
|
if animateLogo {
|
||||||
Image(systemName: "plus.square.dashed")
|
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||||
.resizable()
|
.mask(
|
||||||
.scaledToFit()
|
Image(systemName: "plus.square.dashed")
|
||||||
.frame(width: 120, height: 120, alignment: .center)
|
.resizable()
|
||||||
.padding()
|
.scaledToFit()
|
||||||
.fontWeight(.ultraLight)
|
.frame(width: 120, height: 120, alignment: .center)
|
||||||
.offset(x: 5, y: 5)
|
.padding()
|
||||||
)
|
.fontWeight(.ultraLight)
|
||||||
|
.offset(x: 5, y: 5)
|
||||||
|
)
|
||||||
|
.phaseAnimator([false, true]) { wwdc24, chromaRotate in
|
||||||
|
wwdc24
|
||||||
|
.hueRotation(.degrees(chromaRotate ? 420 : 0))
|
||||||
|
} animation: { chromaRotate in
|
||||||
|
.easeInOut(duration: 6)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||||
|
.mask(
|
||||||
|
Image(systemName: "plus.square.dashed")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 120, height: 120, alignment: .center)
|
||||||
|
.padding()
|
||||||
|
.fontWeight(.ultraLight)
|
||||||
|
.offset(x: 5, y: 5)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
|
||||||
|
.mask(
|
||||||
|
Image(systemName: "plus.square.dashed")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 120, height: 120, alignment: .center)
|
||||||
|
.padding()
|
||||||
|
.fontWeight(.ultraLight)
|
||||||
|
.offset(x: 5, y: 5)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Text("Drop your app here")
|
|
||||||
|
|
||||||
|
Text("Drop an app here")
|
||||||
.font(.title3)
|
.font(.title3)
|
||||||
.padding(.bottom, 25)
|
.padding(.bottom, 25)
|
||||||
.opacity(0.5)
|
.opacity(0.5)
|
||||||
@@ -120,23 +155,23 @@ struct MiniEmptyView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
|
||||||
if appState.isReminderVisible {
|
// if appState.isReminderVisible {
|
||||||
Text("CMD + Z to undo")
|
// Text("CMD + Z to undo")
|
||||||
.font(.title2)
|
// .font(.title2)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
// .foregroundStyle(Color("mode").opacity(0.5))
|
||||||
.fontWeight(.medium)
|
// .fontWeight(.medium)
|
||||||
.onAppear {
|
// .onAppear {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
// DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||||
withAnimation {
|
// withAnimation {
|
||||||
updateOnMain {
|
// updateOnMain {
|
||||||
appState.isReminderVisible = false
|
// appState.isReminderVisible = false
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Spacer()
|
// Spacer()
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -186,6 +221,7 @@ struct MiniAppView: View {
|
|||||||
if appState.currentView != .empty {
|
if appState.currentView != .empty {
|
||||||
SearchBarMiniBottom(search: $search)
|
SearchBarMiniBottom(search: $search)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
|
.padding(.top, 5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.bottom)
|
.padding(.bottom)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ struct RegularMode: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
.frame(width: sidebarWidth)
|
.frame(width: sidebarWidth)
|
||||||
.padding(.vertical)
|
.padding(.vertical, 7)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -107,19 +107,34 @@ struct AppDetailsEmptyView: View {
|
|||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
@EnvironmentObject var locations: Locations
|
@EnvironmentObject var locations: Locations
|
||||||
@State private var animateGradient: Bool = false
|
@AppStorage("settings.general.animateLogo") private var animateLogo: Bool = true
|
||||||
@Binding var showPopover: Bool
|
@Binding var showPopover: Bool
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
if #available(macOS 14, *) {
|
||||||
|
if animateLogo {
|
||||||
|
PearDropView()
|
||||||
|
.phaseAnimator([false, true]) { wwdc24, chromaRotate in
|
||||||
|
wwdc24
|
||||||
|
.hueRotation(.degrees(chromaRotate ? 420 : 0))
|
||||||
|
} animation: { chromaRotate in
|
||||||
|
.easeInOut(duration: 6)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PearDropView()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PearDropView()
|
||||||
|
}
|
||||||
|
|
||||||
PearDropView()
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Text("Drop your app here or select one from the list")
|
Text("Drop an app here")
|
||||||
.font(.title3)
|
.font(.title3)
|
||||||
.padding(.bottom, 25)
|
.padding(.bottom, 25)
|
||||||
.opacity(0.5)
|
.opacity(0.5)
|
||||||
|
|||||||
@@ -20,21 +20,21 @@ struct TopBar: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center, spacing: 0) {
|
HStack(alignment: .center, spacing: 0) {
|
||||||
|
|
||||||
Spacer()
|
// Spacer()
|
||||||
|
//
|
||||||
if appState.isReminderVisible {
|
// if appState.isReminderVisible {
|
||||||
Text("CMD + Z to undo")
|
// Text("CMD + Z to undo")
|
||||||
.font(.title2)
|
// .font(.title2)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
// .foregroundStyle(Color("mode").opacity(0.5))
|
||||||
.fontWeight(.medium)
|
// .fontWeight(.medium)
|
||||||
.onAppear {
|
// .onAppear {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
// DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||||
withAnimation {
|
// withAnimation {
|
||||||
appState.isReminderVisible = false
|
// appState.isReminderVisible = false
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
|||||||
@@ -255,9 +255,9 @@ struct ZombieView: View {
|
|||||||
moveFilesToTrash(at: selectedItemsArray) {
|
moveFilesToTrash(at: selectedItemsArray) {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
showPopover = false
|
showPopover = false
|
||||||
updateOnMain {
|
// updateOnMain {
|
||||||
appState.isReminderVisible.toggle()
|
// appState.isReminderVisible.toggle()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,11 +321,19 @@ struct ZombieFileDetailsItem: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
VStack(alignment: .leading, spacing: 5) {
|
VStack(alignment: .leading, spacing: 5) {
|
||||||
Text(path.lastPathComponent)
|
|
||||||
.font(.title3)
|
HStack(alignment: .center) {
|
||||||
.lineLimit(1)
|
Text(showLocalized(url: path))
|
||||||
.truncationMode(.tail)
|
.font(.title3)
|
||||||
.help(path.lastPathComponent)
|
.lineLimit(1)
|
||||||
|
.truncationMode(.tail)
|
||||||
|
.help(path.lastPathComponent)
|
||||||
|
|
||||||
|
if let imageView = folderImages(for: path.path) {
|
||||||
|
imageView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Text(path.path)
|
Text(path.path)
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user