Skip to content

Commit 4bc6e09

Browse files
committed
merge: bring all changes from claude branch into main
2 parents 55c48ea + f4a1966 commit 4bc6e09

7 files changed

Lines changed: 188 additions & 360 deletions

MacSweep/ApplicationsManagerView.swift

Lines changed: 89 additions & 351 deletions
Large diffs are not rendered by default.

MacSweep/DevCleanerView.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ struct DevCleanerView: View {
1010
@State private var cleanedBytes: Int64 = 0
1111
@State private var showCleanSheet = false
1212
@State private var showResultSheet = false
13+
@State private var showFDAAlert = false
1314
@State private var showNodeModulesSheet = false
1415
@State private var showBuildArtifactsSheet = false
1516
@State private var showCLIToolsSheet = false
@@ -451,7 +452,11 @@ struct DevCleanerView: View {
451452
isCleaning = true
452453
cleanedBytes = await devEngine.cleanSelected()
453454
isCleaning = false
454-
showResultSheet = true
455+
if cleanedBytes == 0 {
456+
showFDAAlert = true
457+
} else {
458+
showResultSheet = true
459+
}
455460
}
456461
}
457462
Button("Cancel", role: .cancel) {}
@@ -461,9 +466,16 @@ struct DevCleanerView: View {
461466
.sheet(isPresented: $showResultSheet) {
462467
DevCleanResultSheet(cleanedBytes: cleanedBytes) {
463468
showResultSheet = false
464-
devEngine.scanAll()
465469
}
466470
}
471+
.alert("Full Disk Access Required", isPresented: $showFDAAlert) {
472+
Button("Open System Settings") {
473+
NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles")!)
474+
}
475+
Button("Cancel", role: .cancel) { }
476+
} message: {
477+
Text("MacSweep needs Full Disk Access to delete dev caches.\n\nGo to System Settings → Privacy & Security → Full Disk Access and enable MacSweep.")
478+
}
467479
}
468480
.padding(.horizontal, 20)
469481
.padding(.vertical, 12)

MacSweep/MacSweepApp.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
133133

134134
guard needsResize else { return }
135135

136+
// Position window in the center of the screen
136137
let targetRect = NSRect(
137138
x: visible.midX - targetWidth / 2,
138139
y: visible.midY - targetHeight / 2,

MacSweep/MenuBarView.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct MenuBarView: View {
133133
}
134134
.frame(width: 840)
135135
.background(bgGradient)
136+
.background(MenuBarPopupPositioner())
136137
.animation(.easeInOut(duration: 0.22), value: settings.menuBarTab)
137138
.onReceive(Timer.publish(every: 3.0, on: .main, in: .common).autoconnect()) { _ in
138139
// Keep menu popup values fresh while it is open.
@@ -3114,3 +3115,52 @@ struct MenuBarStatusRow: View {
31143115
}
31153116
}
31163117
}
3118+
3119+
// MARK: - Menu Bar Popup Positioner
3120+
// Moves the MenuBarExtra popup window to the top-right corner every time it opens.
3121+
private struct MenuBarPopupPositioner: NSViewRepresentable {
3122+
func makeNSView(context: Context) -> NSView {
3123+
let view = _PositionerView()
3124+
return view
3125+
}
3126+
func updateNSView(_ nsView: NSView, context: Context) {}
3127+
}
3128+
3129+
private final class _PositionerView: NSView {
3130+
private var observer: NSObjectProtocol?
3131+
3132+
override func viewDidMoveToWindow() {
3133+
super.viewDidMoveToWindow()
3134+
guard let window else { return }
3135+
positionTopRight(window)
3136+
3137+
// Re-position every time the popup becomes key (i.e. every click on the icon)
3138+
observer = NotificationCenter.default.addObserver(
3139+
forName: NSWindow.didBecomeKeyNotification,
3140+
object: window,
3141+
queue: .main
3142+
) { [weak window] _ in
3143+
guard let window else { return }
3144+
self.positionTopRight(window)
3145+
}
3146+
}
3147+
3148+
override func removeFromSuperview() {
3149+
if let observer { NotificationCenter.default.removeObserver(observer) }
3150+
super.removeFromSuperview()
3151+
}
3152+
3153+
private func positionTopRight(_ window: NSWindow) {
3154+
for delay in [0.05, 0.15, 0.3] {
3155+
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak window] in
3156+
guard let window, window.isVisible else { return }
3157+
guard let screen = window.screen ?? NSScreen.main else { return }
3158+
let visible = screen.visibleFrame
3159+
let size = window.frame.size
3160+
let x = visible.maxX - size.width - 8
3161+
let y = visible.maxY - size.height
3162+
window.setFrameOrigin(NSPoint(x: x, y: y))
3163+
}
3164+
}
3165+
}
3166+
}

MacSweep/PerformanceManagerView.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ struct PerformanceManagerView: View {
88
@State private var selectedGroup: PerformanceGroup.Kind? = .loginItems
99
@State private var showResult = false
1010
@State private var resultMessage = ""
11+
@State private var showFDAAlert = false
1112

1213
@EnvironmentObject var navManager: NavigationManager
1314

@@ -62,10 +63,18 @@ struct PerformanceManagerView: View {
6263
}
6364
.background(DS.bg)
6465
.alert("Action Complete", isPresented: $showResult) {
65-
Button("OK") { engine.scanAll() }
66+
Button("OK") { }
6667
} message: {
6768
Text(resultMessage)
6869
}
70+
.alert("Full Disk Access Required", isPresented: $showFDAAlert) {
71+
Button("Open System Settings") {
72+
NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles")!)
73+
}
74+
Button("Cancel", role: .cancel) { }
75+
} message: {
76+
Text("MacSweep needs Full Disk Access to manage startup items.\n\nGo to System Settings → Privacy & Security → Full Disk Access and enable MacSweep.")
77+
}
6978
}
7079

7180
// MARK: - Landing

MacSweep/PrivacyView.swift

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ struct PrivacyView: View {
55
@ObservedObject var cleanEngine: CleanEngine
66
@State private var showConfirm = false
77
@State private var showResult = false
8+
@State private var showFDAAlert = false
89
@State private var isScanning = false
910
@State private var privacyItems: [PrivacyItem] = []
1011
@State private var scanDone = false
@@ -44,6 +45,14 @@ struct PrivacyView: View {
4445
} message: {
4546
Text("This will clear \(ByteCountFormatter.string(fromByteCount: selectedSize, countStyle: .file)) of privacy-sensitive data.")
4647
}
48+
.alert("Full Disk Access Required", isPresented: $showFDAAlert) {
49+
Button("Open System Settings") {
50+
NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles")!)
51+
}
52+
Button("Cancel", role: .cancel) { }
53+
} message: {
54+
Text("MacSweep needs Full Disk Access to clear privacy data.\n\nGo to System Settings → Privacy & Security → Full Disk Access and enable MacSweep.")
55+
}
4756
}
4857

4958
// MARK: - Scanning View
@@ -230,17 +239,25 @@ struct PrivacyView: View {
230239
}
231240

232241
private func clearPrivacyData() {
233-
let bytesToClear = selectedSize
234242
let fm = FileManager.default
243+
var actualCleared: Int64 = 0
235244
for item in privacyItems where item.isSelected {
236245
let url = URL(fileURLWithPath: item.path)
237-
if (try? fm.trashItem(at: url, resultingItemURL: nil)) == nil {
238-
try? fm.removeItem(at: url)
246+
let deleted: Bool
247+
if (try? fm.trashItem(at: url, resultingItemURL: nil)) != nil {
248+
deleted = true
249+
} else if (try? fm.removeItem(at: url)) != nil {
250+
deleted = true
251+
} else {
252+
deleted = false
239253
}
254+
if deleted { actualCleared += item.size }
240255
}
241-
if bytesToClear > 0 {
242-
scanEngine.recordFreed(bytes: bytesToClear, description: "Privacy cleanup")
256+
if actualCleared == 0 {
257+
showFDAAlert = true
258+
return
243259
}
260+
scanEngine.recordFreed(bytes: actualCleared, description: "Privacy cleanup")
244261
DS.playCleanComplete()
245262
scanPrivacy()
246263
}

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414
---
1515

16-
[![Download MacSweep v3.3 — Free Mac Cleaner DMG](https://img.shields.io/badge/Download%20MacSweep%20v3.3-.DMG%20Installer-169677?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/MehmedHunjra/MacSweep/releases/latest/download/MacSweep-Installer-v3.3.dmg)
16+
[![Download MacSweep v3.3 — DMG](https://img.shields.io/badge/Download%20v3.3-.DMG-169677?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/MehmedHunjra/MacSweep/releases/download/v3.3/MacSweep-3.3.dmg)
17+
[![Download MacSweep v3.3 — ZIP (faster)](https://img.shields.io/badge/Download%20v3.3-.DMG.ZIP%20%E2%80%94%20faster-0e7a60?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/MehmedHunjra/MacSweep/releases/download/v3.3/MacSweep-3.3.dmg.zip)
1718
[![Support MacSweep on Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/K3K21VE53X)
1819

1920
> **macOS 13 Ventura or later · Apple Silicon (M1/M2/M3/M4) & Intel · Free forever · No subscription required**

0 commit comments

Comments
 (0)