Skip to content

Commit 418dd02

Browse files
committed
added UTI prop, updated UI
1 parent fcb9dfb commit 418dd02

File tree

5 files changed

+42
-56
lines changed

5 files changed

+42
-56
lines changed

MacImageManager/MacImageManager/ContentView.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ struct ContentView: View {
1515

1616
var body: some View {
1717
HSplitView {
18-
// Left sidebar - File browser
18+
// Left pane - File browser
1919
PaneFileBrowserView(selectedImage: $selectedImage)
20-
.frame(minWidth: 200, maxWidth: 400)
20+
.frame(minWidth: 250, maxWidth: 400)
2121

2222
// Right pane - Image viewer
2323
PaneImageViewer(selectedImage: selectedImage?.url)
24-
.frame(minWidth: 400)
24+
//.frame(minWidth: 500) // needed?
2525
}
2626
.fileImporter(
2727
isPresented: $browserModel.showingFileImporter,
@@ -39,7 +39,8 @@ struct ContentView: View {
3939
iconName: "folder.fill",
4040
isDirectory: true,
4141
fileSize: 0,
42-
modificationDate: Date()
42+
modificationDate: Date(),
43+
uti: .folder
4344
)
4445
browserModel.navigateInto(item: folderItem)
4546
}

MacImageManager/MacImageManager/Models/BrowserModel+Preview.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,31 @@
66
//
77

88
import Foundation
9+
import UniformTypeIdentifiers
910

1011
#if DEBUG
1112
extension BrowserModel {
1213
static var preview: BrowserModel {
1314
let model = BrowserModel()
14-
15-
// Create a mix of different file types for testing
1615
let now = Date()
1716
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: now)!
1817
let lastWeek = Calendar.current.date(byAdding: .day, value: -7, to: now)!
1918

2019
model.items = [
2120
// Folders
22-
FileItem(url: URL(fileURLWithPath: "/tmp/Photos"), name: "Photos", iconName: "folder.fill", isDirectory: true, fileSize: 0, modificationDate: now),
23-
FileItem(url: URL(fileURLWithPath: "/tmp/Archive"), name: "Archive", iconName: "folder.fill", isDirectory: true, fileSize: 0, modificationDate: lastWeek),
21+
FileItem(url: URL(fileURLWithPath: "/tmp/Photos"), name: "Photos", iconName: "folder.fill", isDirectory: true, fileSize: 0, modificationDate: now, uti: .folder),
22+
FileItem(url: URL(fileURLWithPath: "/tmp/Archive"), name: "Archive", iconName: "folder.fill", isDirectory: true, fileSize: 0, modificationDate: lastWeek, uti: .folder),
2423

2524
// Images with different formats
26-
FileItem(url: URL(fileURLWithPath: "/tmp/vacation.jpg"), name: "vacation.jpg", iconName: "photo", isDirectory: false, fileSize: 2_500_000, modificationDate: now),
27-
FileItem(url: URL(fileURLWithPath: "/tmp/screenshot.png"), name: "screenshot.png", iconName: "photo", isDirectory: false, fileSize: 1_200_000, modificationDate: yesterday),
28-
FileItem(url: URL(fileURLWithPath: "/tmp/animation.gif"), name: "animation.gif", iconName: "photo", isDirectory: false, fileSize: 500_000, modificationDate: lastWeek),
29-
FileItem(url: URL(fileURLWithPath: "/tmp/profile.heic"), name: "profile.heic", iconName: "photo", isDirectory: false, fileSize: 3_000_000, modificationDate: now),
25+
FileItem(url: URL(fileURLWithPath: "/tmp/vacation.jpg"), name: "vacation.jpg", iconName: "photo", isDirectory: false, fileSize: 2_500_000, modificationDate: now, uti: .jpeg),
26+
FileItem(url: URL(fileURLWithPath: "/tmp/screenshot.png"), name: "screenshot.png", iconName: "photo", isDirectory: false, fileSize: 1_200_000, modificationDate: yesterday, uti: .png),
27+
FileItem(url: URL(fileURLWithPath: "/tmp/animation.gif"), name: "animation.gif", iconName: "photo", isDirectory: false, fileSize: 500_000, modificationDate: lastWeek, uti: .gif),
28+
FileItem(url: URL(fileURLWithPath: "/tmp/profile.heic"), name: "profile.heic", iconName: "photo", isDirectory: false, fileSize: 3_000_000, modificationDate: now, uti: .heic),
3029

3130
// Non-image files for testing filtering
32-
FileItem(url: URL(fileURLWithPath: "/tmp/document.pdf"), name: "document.pdf", iconName: "doc", isDirectory: false, fileSize: 150_000, modificationDate: yesterday),
33-
FileItem(url: URL(fileURLWithPath: "/tmp/notes.txt"), name: "notes.txt", iconName: "doc", isDirectory: false, fileSize: 1_024, modificationDate: now)
31+
FileItem(url: URL(fileURLWithPath: "/tmp/document.pdf"), name: "document.pdf", iconName: "doc", isDirectory: false, fileSize: 150_000, modificationDate: yesterday, uti: .pdf),
32+
FileItem(url: URL(fileURLWithPath: "/tmp/notes.txt"), name: "notes.txt", iconName: "doc", isDirectory: false, fileSize: 1_024, modificationDate: now, uti: .text),
33+
FileItem(url: URL(fileURLWithPath: "/tmp/code.js"), name: "code.js", iconName: "doc", isDirectory: false, fileSize: 10_240, modificationDate: yesterday, uti: .javaScript),
3434
]
3535

3636
return model

MacImageManager/MacImageManager/Models/BrowserModel.swift

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -64,70 +64,54 @@ class BrowserModel: ObservableObject {
6464
}
6565

6666
func loadCurrentDirectory() {
67-
// First verify the directory exists and is accessible
68-
var isDirFlag: ObjCBool = false
69-
guard fileManager.fileExists(atPath: currentDirectory.path, isDirectory: &isDirFlag),
70-
isDirFlag.boolValue else {
71-
print("Directory doesn't exist or isn't accessible: \(currentDirectory.path)")
72-
// Fall back to home directory
73-
currentDirectory = fileManager.homeDirectoryForCurrentUser
74-
updateNavigationState()
75-
loadCurrentDirectory()
76-
return
77-
}
78-
79-
print("Loading directory: \(currentDirectory.path)")
80-
8167
do {
8268
let contents = try fileManager.contentsOfDirectory(
8369
at: currentDirectory,
84-
includingPropertiesForKeys: [.isDirectoryKey, .isReadableKey, .fileSizeKey, .contentModificationDateKey],
70+
includingPropertiesForKeys: [.isDirectoryKey, .fileSizeKey, .contentModificationDateKey, .isReadableKey, .contentTypeKey],
8571
options: [.skipsHiddenFiles]
8672
)
8773

8874
var fileItems: [FileItem] = []
8975

9076
for url in contents {
91-
// Skip items we can't read
92-
if let resourceValues = try? url.resourceValues(forKeys: [.isReadableKey]),
93-
let isReadable = resourceValues.isReadable,
94-
!isReadable {
95-
continue
96-
}
97-
98-
let resourceValues = try url.resourceValues(forKeys: [.isDirectoryKey, .fileSizeKey, .contentModificationDateKey])
99-
77+
let resourceValues = try url.resourceValues(forKeys: [.isDirectoryKey, .fileSizeKey, .contentModificationDateKey, .isReadableKey, .contentTypeKey])
78+
79+
// GUARD: Check if the file is readable.
80+
guard resourceValues.isReadable ?? false else { continue }
81+
10082
let isDir = resourceValues.isDirectory ?? false
10183
let fileSize = resourceValues.fileSize ?? 0
10284
let modDate = resourceValues.contentModificationDate ?? Date()
85+
let uti = resourceValues.contentType
10386

104-
// 💡 Determine the icon name based on file type
10587
let iconName: String
10688
if isDir {
10789
iconName = "folder.fill"
90+
} else if uti?.conforms(to: .image) ?? false {
91+
iconName = "photo"
92+
} else if uti?.conforms(to: .movie) ?? false {
93+
iconName = "film"
94+
} else if uti?.conforms(to: .text) ?? false {
95+
iconName = "doc.text"
96+
} else if uti?.conforms(to: .sourceCode) ?? false {
97+
iconName = "doc.text.fill"
10898
} else {
109-
let ext = url.pathExtension.lowercased()
110-
iconName = imageTypes.contains(ext) ? "photo" : "doc"
99+
iconName = "doc"
111100
}
112101

113-
// 💡 Create the new FileItem object
114-
let fileItem = FileItem(url: url, name: url.lastPathComponent, iconName: iconName, isDirectory: isDir, fileSize: fileSize, modificationDate: modDate)
115-
102+
let fileItem = FileItem(url: url, name: url.lastPathComponent, iconName: iconName, isDirectory: isDir, fileSize: fileSize, modificationDate: modDate, uti: uti)
116103
fileItems.append(fileItem)
117104
}
118105

119-
// Sort file items
120106
fileItems.sort { $0.name.localizedCaseInsensitiveCompare($1.name) == .orderedAscending }
121107

122-
// Set items
123108
self.items = fileItems
124109
print("Loaded \(items.count) items.")
125110

126-
// LAST:
127111
updateNavigationState()
112+
128113
} catch {
129114
print("Error loading directory: \(error)")
130-
print("Current directory path: \(currentDirectory.path)")
131115
self.items = []
132116
}
133117
}

MacImageManager/MacImageManager/Models/FileItem.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
import Foundation
99
import UniformTypeIdentifiers
10-
11-
// TODO: add `fileType` (e.g., GIF, Image, Video)
10+
// NOTE: this is the standard macOS method for identifying file types
11+
// ....: and is much more reliable than just checking the file extension.
1212

1313
struct FileItem: Identifiable, Hashable {
1414
let id = UUID()
@@ -18,6 +18,7 @@ struct FileItem: Identifiable, Hashable {
1818
let isDirectory: Bool
1919
let fileSize: Int
2020
let modificationDate: Date
21+
let uti: UTType?
2122

2223
var formattedFileSize: String {
2324
if fileSize < 1024 {

MacImageManager/MacImageManager/Views/FileBrowserRowView.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct FileBrowserRowView: View {
2121
VStack(alignment: .leading) {
2222
Text(item.name)
2323
.lineLimit(1)
24-
Text(item.url.path)
24+
Text(item.modificationDate.formatted(date: .abbreviated, time: .shortened))
2525
.lineLimit(1)
2626
.foregroundColor(.gray)
2727
}
@@ -39,22 +39,22 @@ struct FileBrowserRowView: View {
3939
.contextMenu {
4040
Button(item.isDirectory ? "Rename Folder" : "Rename File") {
4141
if item.isDirectory {
42-
print("TODO: Rename directory functionality")
42+
print("FUTURE: Rename directory functionality")
4343
//browserModel.navigateInto(item: item)
4444
} else {
45-
print("TODO: Rename file functionality")
45+
print("FUTURE: Rename file functionality")
4646
// This could be a new method in your model or a simple action here
4747
}
4848
}
49-
// TODO: Add other menu items as needed
49+
// FUTURE: Add other menu items as needed
5050
Divider()
5151

5252
Button("Rename") {
53-
print("TODO: Implement rename functionality")
53+
print("FUTURE: Implement rename functionality")
5454
}
5555

5656
Button("Get Info") {
57-
print("TODO: Implement get info functionality")
57+
print("FUTURE: Implement get info functionality")
5858
}
5959
}
6060
}

0 commit comments

Comments
 (0)