diff options
| author | Dustin Mierau <dustin@mierau.me> | 2024-07-29 19:07:47 -0700 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2024-07-29 19:07:47 -0700 |
| commit | c6996c3ac262616198e94197d1c6b310d44508ee (patch) | |
| tree | 6a4a3e98b7a2449a3d200bb5f4cc1c3c8b92b4ad /Hotline/macOS/FilesView.swift | |
| parent | 5726ab32f161e4b62ee0d65303b76d9894769c92 (diff) | |
Add drag and drop suppport for files to upload. Tighten up spacing on heirarchical lists. Add some extra HFS type to UTType conversion. Update to latest packages.
Diffstat (limited to 'Hotline/macOS/FilesView.swift')
| -rw-r--r-- | Hotline/macOS/FilesView.swift | 196 |
1 files changed, 141 insertions, 55 deletions
diff --git a/Hotline/macOS/FilesView.swift b/Hotline/macOS/FilesView.swift index e34c7b5..80d89f9 100644 --- a/Hotline/macOS/FilesView.swift +++ b/Hotline/macOS/FilesView.swift @@ -1,39 +1,51 @@ import SwiftUI import UniformTypeIdentifiers -struct FileView: View { +struct FolderView: View { @Environment(Hotline.self) private var model: Hotline - @State var expanded = false @State var loading = false + @State var dragOver = false var file: FileInfo let depth: Int + @MainActor private func uploadFile(file fileURL: URL) { + var filePath: [String] = [String](self.file.path) + if !self.file.isFolder { + filePath.removeLast() + } + + print("UPLOADING TO PATH: ", filePath) + + model.uploadFile(url: fileURL, path: filePath) { info in + Task { + // Refresh file listing to display newly uploaded file. + let _ = await model.getFileList(path: filePath) + } + } + } + var body: some View { HStack(alignment: .center, spacing: 0) { - if file.isFolder { - Button { - if file.isFolder { - file.expanded.toggle() - } - } label: { - Text(Image(systemName: file.expanded ? "chevron.down" : "chevron.right")) - .bold() - .font(.system(size: 10)) - .opacity(0.5) + Spacer() + .frame(width: CGFloat(depth * (12 + 2))) + + Button { + if file.isFolder { + file.expanded.toggle() } - .buttonStyle(.plain) - .frame(width: 10) - .padding(.leading, 4) - .padding(.trailing, 8) - } - else { - Spacer() - .frame(width: 10) - .padding(.leading, 4) - .padding(.trailing, 8) + } label: { + Text(Image(systemName: file.expanded ? "chevron.down" : "chevron.right")) + .bold() + .font(.system(size: 10)) + .foregroundStyle(dragOver ? Color.white : Color.primary) + .opacity(0.5) } + .buttonStyle(.plain) + .frame(width: 10) + .padding(.leading, 4) + .padding(.trailing, 8) HStack(alignment: .center) { if file.isUnavailable { @@ -53,17 +65,11 @@ struct FileView: View { .scaledToFit() .frame(width: 16, height: 16) } - else if file.isFolder { + else { Image("Folder") .resizable() .scaledToFit() .frame(width: 16, height: 16) -// FolderIconView(dropbox: file.isUploadFolder) -// .frame(width: 16, height: 16) - } - else { - FileIconView(filename: file.name) - .frame(width: 16, height: 16) } } .frame(width: 16) @@ -72,47 +78,123 @@ struct FileView: View { Text(file.name) .lineLimit(1) .truncationMode(.tail) + .foregroundStyle(dragOver ? Color.white : Color.primary) .opacity(file.isUnavailable ? 0.5 : 1.0) - if file.isFolder && loading { + if loading { ProgressView().controlSize(.small).padding([.leading, .trailing], 5) } Spacer() if !file.isUnavailable { - if file.isFolder { - Text(file.fileSize == 0 ? "Empty" : "^[\(file.fileSize) \("file")](inflect: true)") - .foregroundStyle(.secondary) - .lineLimit(1) - .padding(.trailing, 6) - } - else { - Text(formattedFileSize(file.fileSize)) - .foregroundStyle(.secondary) - .lineLimit(1) - .padding(.trailing, 6) - } + Text(file.fileSize == 0 ? "Empty" : "^[\(file.fileSize) \("file")](inflect: true)") + .foregroundStyle(dragOver ? Color.white.opacity(0.75) : Color.secondary) + .lineLimit(1) + .padding(.trailing, 6) } } .frame(maxWidth: .infinity, maxHeight: .infinity) - .padding(.leading, CGFloat(depth * (12 + 10))) + .background( + RoundedRectangle(cornerRadius: 4.0) + .fill(dragOver ? Color(nsColor: NSColor.selectedContentBackgroundColor) : Color.clear) + .padding(.horizontal, -6) + .padding(.vertical, -4) + ) .onChange(of: file.expanded) { loading = false - if file.isFolder && file.fileSize > 0 { - if file.expanded { - Task { - loading = true - let _ = await model.getFileList(path: file.path) - loading = false + if file.expanded && file.fileSize > 0 { + Task { + loading = true + let _ = await model.getFileList(path: file.path) + loading = false + } + } + } + .onDrop(of: [.fileURL], isTargeted: $dragOver) { items in + guard let item = items.first, + let identifier = item.registeredTypeIdentifiers.first else { + return false + } + + item.loadItem(forTypeIdentifier: identifier, options: nil) { (urlData, error) in + print("WHAT?", Thread.isMainThread) + DispatchQueue.main.async { + print("WHAT 2?", Thread.isMainThread) + if let urlData = urlData as? Data, + let fileURL = URL(dataRepresentation: urlData, relativeTo: nil, isAbsolute: true) { + // uploadFile(file: fileURL) } } } + + return true } if file.expanded { ForEach(file.children!, id: \.self) { childFile in - FileView(file: childFile, depth: self.depth + 1).tag(file.id) -// .environment(self.selectedFile) -// .frame(height: 34) + if childFile.isFolder { + FolderView(file: childFile, depth: self.depth + 1).tag(file.id) + } + else { + FileView(file: childFile, depth: self.depth + 1).tag(file.id) + } + } + } + } +} + +struct FileView: View { + @Environment(Hotline.self) private var model: Hotline + + var file: FileInfo + let depth: Int + + var body: some View { + HStack(alignment: .center, spacing: 0) { + Spacer() + .frame(width: CGFloat(depth * (12 + 2))) + + Spacer() + .frame(width: 10) + .padding(.leading, 4) + .padding(.trailing, 8) + + HStack(alignment: .center) { + if file.isUnavailable { + Image(systemName: "questionmark.app.fill") + .frame(width: 16, height: 16) + .opacity(0.5) + } + else { + FileIconView(filename: file.name, fileType: file.type) + .frame(width: 16, height: 16) + } + } + .frame(width: 16) + .padding(.trailing, 6) + + Text(file.name) + .lineLimit(1) + .truncationMode(.tail) + .opacity(file.isUnavailable ? 0.5 : 1.0) + + Spacer() + if !file.isUnavailable { + Text(formattedFileSize(file.fileSize)) + .foregroundStyle(.secondary) + .lineLimit(1) + .padding(.trailing, 6) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + + if file.expanded { + ForEach(file.children!, id: \.self) { childFile in + if childFile.isFolder { + FolderView(file: childFile, depth: self.depth + 1).tag(file.id) + } + else { + FileView(file: childFile, depth: self.depth + 1).tag(file.id) + } } } } @@ -120,7 +202,6 @@ struct FileView: View { static let byteFormatter = ByteCountFormatter() private func formattedFileSize(_ fileSize: UInt) -> String { - // let bcf = ByteCountFormatter() FileView.byteFormatter.allowedUnits = [.useAll] FileView.byteFormatter.countStyle = .file return FileView.byteFormatter.string(fromByteCount: Int64(fileSize)) @@ -199,9 +280,14 @@ struct FilesView: View { var body: some View { NavigationStack { List(model.files, id: \.self, selection: $selection) { file in - FileView(file: file, depth: 0).tag(file.id) + if file.isFolder { + FolderView(file: file, depth: 0).tag(file.id) + } + else { + FileView(file: file, depth: 0).tag(file.id) + } } - .environment(\.defaultMinListRowHeight, 34) + .environment(\.defaultMinListRowHeight, 28) .listStyle(.inset) .alternatingRowBackgrounds(.enabled) .task { |