diff options
| author | Dustin Mierau <dustin@mierau.me> | 2024-01-01 11:35:49 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2024-01-01 11:35:49 -0800 |
| commit | 5d2aadbc834393b532d043d6298d6a23b80c2a5c (patch) | |
| tree | dcf139b67179d5bc3ad3ed69e949a1e7c1d18177 /Hotline/macOS | |
| parent | a4cbaea0b12b7dd42133b4bd14f1371f1000fcc0 (diff) | |
File downloads now working in macOS client.1.0beta4
Diffstat (limited to 'Hotline/macOS')
| -rw-r--r-- | Hotline/macOS/ChatView.swift | 1 | ||||
| -rw-r--r-- | Hotline/macOS/FilesView.swift | 14 | ||||
| -rw-r--r-- | Hotline/macOS/MessageView.swift | 1 | ||||
| -rw-r--r-- | Hotline/macOS/ServerView.swift | 301 | ||||
| -rw-r--r-- | Hotline/macOS/TrackerView.swift | 4 |
5 files changed, 218 insertions, 103 deletions
diff --git a/Hotline/macOS/ChatView.swift b/Hotline/macOS/ChatView.swift index 618fd12..4399de6 100644 --- a/Hotline/macOS/ChatView.swift +++ b/Hotline/macOS/ChatView.swift @@ -110,7 +110,6 @@ struct ChatView: View { print("SCROLLED TO BOTTOM") } .onAppear { - print("SCROLLED TO BOTTOM ON APPEAR") reader.scrollTo(bottomID, anchor: .bottom) // focusedField = .chatInput } diff --git a/Hotline/macOS/FilesView.swift b/Hotline/macOS/FilesView.swift index 771836d..09354ed 100644 --- a/Hotline/macOS/FilesView.swift +++ b/Hotline/macOS/FilesView.swift @@ -138,6 +138,10 @@ struct FilesView: View { if clickedFile.isFolder { clickedFile.expanded.toggle() } + else { + print("DOWNLOAD FILE", clickedFile.name, clickedFile.path) + model.downloadFile(clickedFile.name, path: clickedFile.path) + } } .onKeyPress(.rightArrow) { if let s = selection, s.isFolder { @@ -175,6 +179,12 @@ struct FilesView: View { ToolbarItem(placement: .primaryAction) { Button { + if let s = selection, !s.isFolder { + print("DOWNLOAD FILE", s.name, s.path) + model.previewFile(s.name, path: s.path, addTransfer: true) { transfer, fileData in + print("FILE PREVIEWED?", fileData.count) + } + } } label: { Label("Preview File", systemImage: "eye") } @@ -191,6 +201,10 @@ struct FilesView: View { ToolbarItem(placement: .primaryAction) { Button { + if let s = selection, !s.isFolder { + print("DOWNLOAD FILE", s.name, s.path) + model.downloadFile(s.name, path: s.path) + } } label: { Label("Download File", systemImage: "square.and.arrow.down") } diff --git a/Hotline/macOS/MessageView.swift b/Hotline/macOS/MessageView.swift index 19b48f2..e880435 100644 --- a/Hotline/macOS/MessageView.swift +++ b/Hotline/macOS/MessageView.swift @@ -88,7 +88,6 @@ struct MessageView: View { print("SCROLLED TO BOTTOM") } .onAppear { - print("SCROLLED TO BOTTOM ON APPEAR") reader.scrollTo(bottomID, anchor: .bottom) } .scrollDismissesKeyboard(.interactively) diff --git a/Hotline/macOS/ServerView.swift b/Hotline/macOS/ServerView.swift index 337882b..7d89481 100644 --- a/Hotline/macOS/ServerView.swift +++ b/Hotline/macOS/ServerView.swift @@ -1,4 +1,5 @@ import SwiftUI +import UniformTypeIdentifiers enum MenuItemType { case banner @@ -51,47 +52,108 @@ struct ListItemView: View { } } -struct AgreementView: View { - @Environment(\.dismiss) var dismiss +struct TransferItemView: View { + let transfer: TransferInfo - let text: String - let disagree: (() -> Void)? - let agree: (() -> Void)? + private func fileIcon(name: String) -> Image { + let fileExtension = (name as NSString).pathExtension + return Image(nsImage: NSWorkspace.shared.icon(for: UTType(filenameExtension: fileExtension) ?? UTType.content)) + } + + @Environment(Hotline.self) private var model: Hotline + @State private var hovered: Bool = false + @State private var buttonHovered: Bool = false + + private func formattedProgressHelp() -> String { + if self.transfer.completed { + return "File transfer complete" + } + else if self.transfer.failed { + return "File transfer failed" + } + else if self.transfer.progress > 0.0 { + if self.transfer.timeRemaining > 0.0 { + return "\(round(self.transfer.progress * 100.0))% – \(self.transfer.timeRemaining) seconds left" + } + else { + return "\(round(self.transfer.progress * 100.0))% complete" + } + } + return "" + } var body: some View { - VStack(spacing: 0) { - ScrollView(.vertical) { - Text(text) - .padding() - .font(.system(size: 13)) - .fontDesign(.monospaced) - .textSelection(.enabled) - .lineSpacing(3) - .frame(maxWidth: .infinity, alignment: .leading) + HStack(alignment: .center) { + HStack(spacing: 0) { + Spacer() + fileIcon(name: transfer.title) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 16, height: 16) + Spacer() } - .frame(maxWidth: .infinity) - Divider() - HStack(spacing: 8) { - Button("Disagree", action: { - dismiss() - disagree?() - }) - .controlSize(.large) - .frame(width: 80) - .keyboardShortcut(.cancelAction) - - Button("Agree", action: { - dismiss() - agree?() - }) - .controlSize(.large) - .frame(width: 80) - .keyboardShortcut(.defaultAction) + .frame(width: 18) + + Text(transfer.title) + .lineLimit(1) + .truncationMode(.middle) + + Spacer() + + if self.hovered { + Button { + model.deleteTransfer(id: transfer.id) + } label: { + if transfer.completed { + Image(systemName: self.buttonHovered ? "xmark.circle.fill" : "xmark.circle") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 16, height: 16) + .opacity(self.buttonHovered ? 1.0 : 0.5) + } + else { + Image(systemName: self.buttonHovered ? "trash.circle.fill" : "trash.circle") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 16, height: 16) + .opacity(self.buttonHovered ? 1.0 : 0.5) + } + } + .buttonStyle(.plain) + .padding(0) + .frame(width: 16, height: 16) + .help(transfer.completed || transfer.failed ? "Remove" : "Cancel Transfer") + .onHover { hovered in + self.buttonHovered = hovered + } + } + else if transfer.failed { + Image(systemName: "exclamationmark.triangle") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 16, height: 16) + } + else if transfer.completed { + Image(systemName: "checkmark.circle.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 16, height: 16) + } + else if transfer.progress == 0.0 { + ProgressView() + .progressViewStyle(.circular) + .controlSize(.small) } - .frame(maxWidth: .infinity) - .padding(16) + else { + ProgressView(value: transfer.progress, total: 1.0) + .progressViewStyle(.circular) + .controlSize(.small) + } + } + .onHover { hovered in + self.hovered = hovered } - .frame(width: 500, height: 500) + .help(formattedProgressHelp()) } } @@ -126,7 +188,6 @@ struct ServerView: View { MenuItem(name: "News", image: "newspaper", type: .news, serverVersion: 150), MenuItem(name: "Board", image: "note.text", type: .messageBoard), MenuItem(name: "Files", image: "folder", type: .files), -// MenuItem(name: "Tasks", image: "arrow.up.circle", type: .tasks), ] @MainActor func sendPreferences() { @@ -151,78 +212,118 @@ struct ServerView: View { } } - var body: some View { - NavigationSplitView { - List(selection: $selection) { - - if model.status != .loggedIn { - HStack { - ProgressView(value: connectionStatusToProgress(status: model.status)) - .padding() + var navigationList: some View { + List(selection: $selection) { + + if model.status != .loggedIn { + HStack { + ProgressView(value: connectionStatusToProgress(status: model.status)) + .padding() + } + .tag(MenuItem(name: "progress", image: "", type: .progress)) + .frame(maxWidth: .infinity, minHeight: 60) + .selectionDisabled() + } + + if model.status == .loggedIn { + ForEach(ServerView.menuItems) { menuItem in + if let minServerVersion = menuItem.serverVersion { + if let v = model.serverVersion, v >= minServerVersion { + ListItemView(icon: menuItem.image, title: menuItem.name) + .tag(menuItem) + } + } + else { + ListItemView(icon: menuItem.image, title: menuItem.name) + .tag(menuItem) } - .tag(MenuItem(name: "progress", image: "", type: .progress)) - .frame(maxWidth: .infinity, minHeight: 60) - .selectionDisabled() } - if model.status == .loggedIn { - ForEach(ServerView.menuItems) { menuItem in - if let minServerVersion = menuItem.serverVersion { - if let v = model.serverVersion, v >= minServerVersion { - ListItemView(icon: menuItem.image, title: menuItem.name) - .tag(menuItem) - } + if model.transfers.count > 0 { + self.transfersSection + } + + if model.users.count > 0 { + self.usersSection + } + } + } + } + + var transfersSection: some View { + Section("Transfers") { + ForEach(model.transfers) { transfer in + TransferItemView(transfer: transfer) + } + } + } + + var usersSection: some View { + Section("Users") { + ForEach(model.users) { user in + HStack { + if let iconString = Hotline.defaultIconSet[Int(user.iconID)] { + Text(iconString) + .font(.headline) + .frame(width: 18) + .opacity(controlActiveState == .inactive ? 0.5 : 1.0) + } + else { + Text("") + .frame(width: 18) + } + + if user.isAdmin { + if user.isIdle { + Text(user.name) + .foregroundStyle(.red) + .opacity(controlActiveState == .inactive ? 0.3 : 0.5) } else { - ListItemView(icon: menuItem.image, title: menuItem.name) - .tag(menuItem) + Text(user.name) + .foregroundStyle(.red) + .opacity(controlActiveState == .inactive ? 0.5 : 1.0) } } - - if model.users.count > 0 { - Section("Users") { - ForEach(model.users) { user in - HStack { - if let iconString = Hotline.defaultIconSet[Int(user.iconID)] { - Text(iconString) - .font(.headline) - .frame(width: 18) - .opacity(controlActiveState == .inactive ? 0.5 : 1.0) - } - else { - Text("") - .frame(width: 18) - } - - if user.status.contains(.admin) { - if user.status.contains(.idle) { - Text(user.name) - .foregroundStyle(.red) - .opacity(controlActiveState == .inactive ? 0.3 : 0.5) - } - else { - Text(user.name) - .foregroundStyle(.red) - .opacity(controlActiveState == .inactive ? 0.5 : 1.0) - } - } - else if user.status.contains(.idle) { - Text(user.name) - .opacity(controlActiveState == .inactive ? 0.3 : 0.5) - } - else { - Text(user.name) + else if user.isIdle { + Text(user.name) + .opacity(controlActiveState == .inactive ? 0.3 : 0.5) + } + else { + Text(user.name) // .opacity(controlActiveState == .inactive ? 0.5 : 1.0) - } - Spacer() - } - .tag(MenuItem(name: user.name, image: "", type: .user, userID: user.id)) - } - } } + Spacer() } + .tag(MenuItem(name: user.name, image: "", type: .user, userID: user.id)) } - .frame(minWidth: 200, idealWidth: 200) + } + } + + var body: some View { + NavigationSplitView { + + self.navigationList + .frame(maxWidth: .infinity) + .navigationSplitViewColumnWidth(min: 150, ideal: 200, max: 500) + +// VSplitView { +// +// self.navigationList +// +// ScrollView { +// VStack(alignment: .leading) { +// // ForEach(model.downloads) { +// // } +// } +// .frame(maxWidth: .infinity) +// } +// +// } +// .frame(maxWidth: .infinity) +// .navigationSplitViewColumnWidth(min: 150, ideal: 200, max: 500) + + } detail: { if let selection = self.selection { switch selection.type { @@ -234,18 +335,22 @@ struct ServerView: View { ChatView() .navigationTitle(self.model.serverTitle) .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") + .navigationSplitViewColumnWidth(min: 250, ideal: 500) case .news: NewsView() .navigationTitle(self.model.serverTitle) .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") + .navigationSplitViewColumnWidth(min: 250, ideal: 500) case .messageBoard: MessageBoardView() .navigationTitle(self.model.serverTitle) .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") + .navigationSplitViewColumnWidth(min: 250, ideal: 500) case .files: FilesView() .navigationTitle(self.model.serverTitle) .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") + .navigationSplitViewColumnWidth(min: 250, ideal: 500) case .tasks: EmptyView() case .user: @@ -253,13 +358,13 @@ struct ServerView: View { MessageView(userID: selectionUserID) .navigationTitle(self.model.serverTitle) .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") + .navigationSplitViewColumnWidth(min: 250, ideal: 500) } } } } .navigationTitle("") .onAppear { - print(" YAYY") self.model.login(server: self.server, login: "", password: "", username: preferences.username, iconID: preferences.userIconID) { success in if !success { print("FAILED LOGIN??") diff --git a/Hotline/macOS/TrackerView.swift b/Hotline/macOS/TrackerView.swift index 789b2cd..3870a38 100644 --- a/Hotline/macOS/TrackerView.swift +++ b/Hotline/macOS/TrackerView.swift @@ -13,7 +13,7 @@ struct TrackerBookmark { @Observable class TrackerItem: Identifiable, Hashable { - @ObservationIgnored let id: UUID = UUID() + let id: UUID = UUID() let bookmark: TrackerBookmark? let server: Server? @@ -86,8 +86,6 @@ class TrackerItem: Identifiable, Hashable { } struct TrackerItemView: View { -// @Environment(Hotline.self) private var model: Hotline - @State var expanded = false @State var loading = false |