aboutsummaryrefslogtreecommitdiff
path: root/Hotline/iOS/FilesView.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Hotline/iOS/FilesView.swift')
-rw-r--r--Hotline/iOS/FilesView.swift145
1 files changed, 145 insertions, 0 deletions
diff --git a/Hotline/iOS/FilesView.swift b/Hotline/iOS/FilesView.swift
new file mode 100644
index 0000000..5815ca2
--- /dev/null
+++ b/Hotline/iOS/FilesView.swift
@@ -0,0 +1,145 @@
+import SwiftUI
+import UniformTypeIdentifiers
+
+struct FileView: View {
+ @Environment(Hotline.self) private var model: Hotline
+
+ @State var expanded = false
+
+ var file: FileInfo
+
+ var body: some View {
+ if file.isFolder {
+ DisclosureGroup(isExpanded: $expanded) {
+ ForEach(file.children!) { childFile in
+ FileView(file: childFile)
+ .frame(height: 44)
+ }
+ } label: {
+ HStack {
+ HStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/) {
+ Image(systemName: "folder.fill")
+ }
+ .frame(minWidth: 25)
+ Text(file.name).fontWeight(.medium).lineLimit(1).truncationMode(.tail)
+ Spacer()
+ Text("\(file.fileSize)").foregroundStyle(.secondary).lineLimit(1)
+ }
+ }
+ .onChange(of: expanded) {
+ if !expanded {
+ return
+ }
+
+ Task {
+ await model.getFileList(path: file.path)
+ }
+ }
+ }
+ else {
+ HStack {
+ HStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/) {
+ fileIcon(name: file.name)
+ .renderingMode(.template)
+ }
+ .frame(minWidth: 25)
+ Text(file.name).lineLimit(1).truncationMode(.tail)
+ Spacer()
+ Text(formattedFileSize(file.fileSize)).foregroundStyle(.secondary).lineLimit(1)
+ }
+ }
+ }
+
+ 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 {
+ // func utTypeForFilename(_ filename: String) -> UTType? {
+ let fileExtension = (name as NSString).pathExtension
+ if let fileType = UTType(filenameExtension: fileExtension) {
+ print("\(name) \(fileExtension) = \(fileType)")
+
+ if fileType.isSubtype(of: .movie) {
+ return Image(systemName: "play.rectangle")
+// return UIImage(systemName: "play.rectangle")!
+ }
+ else if fileType.isSubtype(of: .image) {
+ return Image(systemName: "photo")
+// return UIImage(systemName: "photo")!
+ }
+ else if fileType.isSubtype(of: .archive) {
+ return Image(systemName: "doc.zipper")
+// return UIImage(systemName: "doc.zipper")!
+ }
+ else if fileType.isSubtype(of: .text) {
+ return Image(systemName: "doc.text")
+// return UIImage(systemName: "doc.text")!
+ }
+ else {
+ return Image(systemName: "doc")
+// return UIImage(systemName: "doc")!
+ }
+ }
+
+ return Image(systemName: "doc")
+ }
+}
+
+struct FilesView: View {
+ @Environment(Hotline.self) private var model: Hotline
+
+ @State var initialLoadComplete = false
+
+ var body: some View {
+ NavigationStack {
+ List(model.files) { file in
+ FileView(file: file)
+ .frame(height: 44)
+ }
+ .task {
+ if !initialLoadComplete {
+ let _ = await model.getFileList()
+ initialLoadComplete = true
+ }
+ }
+ .overlay {
+ if !initialLoadComplete {
+ VStack {
+ ProgressView()
+ .controlSize(.large)
+ }
+ .frame(maxWidth: .infinity)
+ }
+ }
+ .listStyle(.plain)
+ .navigationBarTitleDisplayMode(.inline)
+ .toolbar {
+ ToolbarItem(placement: .principal) {
+ Text(model.serverTitle)
+ .font(.headline)
+ }
+ ToolbarItem(placement: .navigationBarLeading) {
+ Button {
+ model.disconnect()
+ } label: {
+ Text(Image(systemName: "xmark.circle.fill"))
+ .symbolRenderingMode(.hierarchical)
+ .font(.title2)
+ .foregroundColor(.secondary)
+ }
+ }
+ }
+ }
+ }
+}
+
+#Preview {
+ FilesView()
+ .environment(Hotline(trackerClient: HotlineTrackerClient(), client: HotlineClient()))
+}