diff options
| author | Dustin Mierau <dustin@mierau.me> | 2023-12-19 20:38:13 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2023-12-19 20:38:13 -0800 |
| commit | 4fd69c02a3e7b581bb9229865336c315153f3b18 (patch) | |
| tree | e6e11d872424196f2b4033077902126ad5556e40 /Hotline/macOS/FilesView.swift | |
| parent | 5e87b5927cd931d46fb5f72fb035480a95969a9f (diff) | |
Beginnings of a UI for macOS as well as some visual changes to iOS client. :)
Diffstat (limited to 'Hotline/macOS/FilesView.swift')
| -rw-r--r-- | Hotline/macOS/FilesView.swift | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/Hotline/macOS/FilesView.swift b/Hotline/macOS/FilesView.swift new file mode 100644 index 0000000..534dd10 --- /dev/null +++ b/Hotline/macOS/FilesView.swift @@ -0,0 +1,174 @@ +import SwiftUI +import UniformTypeIdentifiers + +@Observable +class FileSelection: Equatable { + var selectedFile: FileInfo? = nil + + static func == (lhs: FileSelection, rhs: FileSelection) -> Bool { + return lhs.selectedFile == rhs.selectedFile + } +} + + +struct FileView: View { + @Environment(Hotline.self) private var model: Hotline + + @State var expanded = false + @State var loading = false + + var file: FileInfo + let depth: Int + + var body: some View { + HStack { + if file.isFolder { + Button { + if file.isFolder { + file.expanded.toggle() + } + } label: { + Image(systemName: file.expanded ? "chevron.down" : "chevron.right") + .renderingMode(.template) + .frame(width: 10, height: 10) + .aspectRatio(contentMode: .fit) + .opacity(0.5) + } + .buttonStyle(.plain) + .frame(width: 12) + } + else { + HStack { + + }.frame(width: 12) + } + HStack(alignment: .center) { + if file.isFolder { + Image(systemName: "folder.fill") + } + else { + fileIcon(name: file.name) + .resizable() + .scaledToFill() + .frame(width: 16, height: 16) + } + } + .frame(width: 15) + Text(file.name).lineLimit(1).truncationMode(.tail) + Spacer() + if file.isFolder { + if loading { + ProgressView().controlSize(.small).padding(.trailing, 4) + } + Text("^[\(file.fileSize) file](inflect: true)") + .foregroundStyle(.secondary) + .lineLimit(1) + } + else { + Text(formattedFileSize(file.fileSize)).foregroundStyle(.secondary).lineLimit(1) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .padding(.leading, CGFloat(depth * (12 + 10))) + .onChange(of: file.expanded) { + loading = false + if file.isFolder { + print("EXPANDED \(file.name)? \(expanded)") + if file.expanded { + Task { + loading = true + let _ = await model.getFileList(path: file.path) + loading = false + } + } + } + } + + 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) + } + } + } + + 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)) + } + + private func fileIcon(name: String) -> Image { + let fileExtension = (name as NSString).pathExtension + return Image(nsImage: NSWorkspace.shared.icon(for: UTType(filenameExtension: fileExtension) ?? UTType.content)) + } +} + +struct FilesView: View { + @Environment(Hotline.self) private var model: Hotline + + @State private var selection: FileInfo? + + var body: some View { + NavigationStack { + List(model.files, id: \.self, selection: $selection) { file in + FileView(file: file, depth: 0).tag(file.id) +// .environment(self.fileSelection) +// .frame(height: 34) + } + .environment(\.defaultMinListRowHeight, 34) + .listStyle(.inset) + .alternatingRowBackgrounds(.enabled) + .task { + if !model.filesLoaded { + let _ = await model.getFileList() + } + } + .contextMenu(forSelectionType: FileInfo.self) { items in + // ... + } primaryAction: { items in + print("ITEMS?", items) + guard let clickedFile = items.first else { + return + } + + self.selection = clickedFile + if clickedFile.isFolder { + clickedFile.expanded.toggle() + } + } + .onKeyPress(.rightArrow) { + if let s = selection, s.isFolder { + s.expanded = true + return .handled + } + return .ignored + } + .onKeyPress(.leftArrow) { + if let s = selection, s.isFolder { + s.expanded = false + return .handled + } + return .ignored + } + .overlay { + if !model.filesLoaded { + VStack { + ProgressView() + .controlSize(.large) + } + .frame(maxWidth: .infinity) + } + } + } + } +} + +#Preview { + FilesView() + .environment(Hotline(trackerClient: HotlineTrackerClient(), client: HotlineClient())) +} |