Skip to content

feat: hover-to-reveal actions in app file list#40

Merged
momenbasel merged 2 commits intomomenbasel:mainfrom
zeck00:feat/hover-uninstall
Apr 18, 2026
Merged

feat: hover-to-reveal actions in app file list#40
momenbasel merged 2 commits intomomenbasel:mainfrom
zeck00:feat/hover-uninstall

Conversation

@zeck00
Copy link
Copy Markdown
Contributor

@zeck00 zeck00 commented Apr 15, 2026

Summary

  • File rows in the app uninstaller show Reveal in Finder and Remove buttons on hover
  • Single-file removal with confirmation dialog (instead of only bulk removal)
  • Subtle background highlight on hover with smooth 150ms animation
  • Extracted FileRow component for cleaner separation

As suggested in the closed PR discussions — bringing the hover-to-reveal uninstall UX to v2's AppFilesView.

Test plan

  • Go to Installed Apps, select an app with discovered files
  • Hover over file rows — verify folder and trash icons appear
  • Click folder icon — verify file is revealed in Finder
  • Click trash icon — verify confirmation dialog appears
  • Confirm removal — verify file is removed from the list
  • Verify hover highlight is subtle and animates smoothly

🤖 Generated with Claude Code

zeck00 and others added 2 commits April 15, 2026 10:49
- File rows show Reveal in Finder and Remove buttons on hover
- Single-file removal with confirmation dialog
- Subtle background highlight on hover with smooth animation
- Extracted FileRow component for cleaner code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix app size showing 1 byte: replace kMDItemFSSize (returns directory
  entry size) with totalFileAllocatedSize for accurate bundle sizes
- Increase file enumeration limit from 5000 to 10000 for large apps
- Use Finder via AppleScript for file removal — triggers system auth
  prompt and works with macOS permission model
- Show error alert with "Open System Settings" button when removal
  fails due to missing Full Disk Access
- Verify files are actually gone from disk before removing from UI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@zeck00
Copy link
Copy Markdown
Contributor Author

zeck00 commented Apr 15, 2026

Note: When building locally without code signing (ad-hoc CODE_SIGN_IDENTITY="-"), PureMac won't appear in System Settings → Privacy & Security → Full Disk Access. This is a macOS limitation, only properly code-signed apps register in the TCC/FDA pane. File removal will fail with permission errors in unsigned builds. This works correctly when built with a valid Developer ID signing identity.

@momenbasel momenbasel requested a review from Copilot April 18, 2026 07:23
@momenbasel momenbasel merged commit 2356162 into momenbasel:main Apr 18, 2026
3 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds hover-revealed per-file actions to the Installed Apps “discovered files” list, enabling quick Reveal-in-Finder and single-file removal flows while improving row presentation and app size calculation.

Changes:

  • Extracts a FileRow component with hover-to-reveal action buttons and a per-file confirmation dialog.
  • Updates removal flow to use Finder (AppleScript) to move selected files to Trash and surfaces removal failures via a new removalError.
  • Revises app size calculation to prefer totalFileAllocatedSize and improves the file enumeration fallback.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 8 comments.

File Description
PureMac/Views/Apps/AppFilesView.swift Introduces FileRow, hover actions, single-file remove confirmation, and a removal-failure alert.
PureMac/ViewModels/AppState.swift Adds removalError and changes file removal to Finder/AppleScript “move to Trash” behavior.
PureMac/Logic/Scanning/AppInfoFetcher.swift Updates app size computation to use allocated-size resource values and adjusts enumeration behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +142 to +151
let posixPaths = urls.map { "\"\($0.path)\"" }.joined(separator: ", ")
let script = """
tell application "Finder"
set theFiles to {}
repeat with p in {\(posixPaths)}
set end of theFiles to (POSIX file p as alias)
end repeat
delete theFiles
end tell
"""
Comment on lines +156 to +160
let success = errorInfo == nil
if let errorInfo {
Logger.shared.log("Finder trash error: \(errorInfo)", level: .error)
}
completion(success)
Comment on lines +131 to +133
if failed > 0 {
self.removalError = "\(failed) file\(failed == 1 ? "" : "s") could not be removed. Grant Full Disk Access in System Settings → Privacy & Security to allow PureMac to manage all files."
Logger.shared.log("Failed to remove \(failed) files — likely missing FDA", level: .error)
guard let enumerator = fileManager.enumerator(
at: url,
includingPropertiesForKeys: [.fileSizeKey, .isRegularFileKey],
includingPropertiesForKeys: [.totalFileAllocatedSizeKey, .isRegularFileKey],
Comment on lines +126 to +127
self.discoveredFiles.removeAll { removed.contains($0) }
self.selectedFiles.subtract(removed)
Comment on lines +206 to +210
.alert("Remove \(fileURL.lastPathComponent)?", isPresented: $showConfirmation) {
Button("Cancel", role: .cancel) {}
Button("Remove", role: .destructive) { onRemove() }
} message: {
Text("This will permanently delete this file. This action cannot be undone.")
Comment on lines +165 to +187
if isHovering {
Button {
NSWorkspace.shared.selectFile(fileURL.path, inFileViewerRootedAtPath: "")
} label: {
Image(systemName: "folder")
.font(.caption)
.foregroundStyle(.secondary)
}
.buttonStyle(.plain)
.help("Reveal in Finder")
.transition(.opacity)

Button {
showConfirmation = true
} label: {
Image(systemName: "trash")
.font(.caption)
.foregroundStyle(.red)
}
.buttonStyle(.plain)
.help("Remove this file")
.transition(.opacity)
}
Comment on lines +129 to +131
private func removeSingleFile(_ url: URL) {
appState.selectedFiles = [url]
appState.removeSelectedFiles()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants