aboutsummaryrefslogtreecommitdiff
path: root/Hotline/macOS/FilesView.swift
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2023-12-19 20:38:13 -0800
committerDustin Mierau <dustin@mierau.me>2023-12-19 20:38:13 -0800
commit4fd69c02a3e7b581bb9229865336c315153f3b18 (patch)
treee6e11d872424196f2b4033077902126ad5556e40 /Hotline/macOS/FilesView.swift
parent5e87b5927cd931d46fb5f72fb035480a95969a9f (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.swift174
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()))
+}