diff options
| author | Dustin Mierau <dustin@mierau.me> | 2023-12-22 17:37:13 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2023-12-22 17:37:13 -0800 |
| commit | 4ddc0699afedae39fa27e134bec05330426f2120 (patch) | |
| tree | ce0936e7c537ef527c6472b746b8ef16e471c912 /Hotline/macOS | |
| parent | 3d26737cccd57fcbb5289874363f030ecef77573 (diff) | |
Some work to get banner images working. Some plumbing to get file transfers working though they don't yet. Moving some code away from async/await.
Diffstat (limited to 'Hotline/macOS')
| -rw-r--r-- | Hotline/macOS/ChatView.swift | 104 | ||||
| -rw-r--r-- | Hotline/macOS/FileImageView.swift | 56 | ||||
| -rw-r--r-- | Hotline/macOS/NewsView.swift | 30 | ||||
| -rw-r--r-- | Hotline/macOS/ServerView.swift | 166 | ||||
| -rw-r--r-- | Hotline/macOS/TrackerView.swift | 5 |
5 files changed, 259 insertions, 102 deletions
diff --git a/Hotline/macOS/ChatView.swift b/Hotline/macOS/ChatView.swift index 294f13b..f16ac8b 100644 --- a/Hotline/macOS/ChatView.swift +++ b/Hotline/macOS/ChatView.swift @@ -7,6 +7,7 @@ enum FocusedField: Int, Hashable { struct ChatView: View { @Environment(Hotline.self) private var model: Hotline @Environment(\.colorScheme) var colorScheme + @Environment(\.dismiss) var dismiss @State var input: String = "" @State private var scrollPos: Int? @@ -26,26 +27,56 @@ struct ChatView: View { GeometryReader { gm in ScrollView(.vertical) { LazyVStack(alignment: .leading) { + ForEach(model.chat) { msg in // MARK: Agreement if msg.type == .agreement { - if !msg.text.isEmpty { - HStack { - VStack(alignment: .leading) { - Text(msg.text) - .textSelection(.enabled) - .lineSpacing(4) - .padding(32) - .opacity(0.75) + VStack(alignment: .center) { + + FileImageView() + .environment(self.model) + .frame(maxWidth: 468.0) + .clipShape(RoundedRectangle(cornerRadius: 8)) + + VStack(spacing: 0) { + ScrollView(.vertical) { + HStack { + Text(msg.text) + .font(.system(size: 12)) + .fontDesign(.monospaced) + .textSelection(.enabled) + Spacer() + } + .padding(16) } - .frame(minWidth: 150, maxWidth: 450, alignment: .center) - .background(VisualEffectView(material: .titlebar, blendingMode: .withinWindow).cornerRadius(24)) - .padding() + .scrollBounceBehavior(.basedOnSize) + .frame(maxHeight: 325) + +// Divider() +// +// HStack { +// Button("Disagree") { +// dismiss() +// } +// .controlSize(.large) +// +// Spacer() +// +// Button("Agree") { +// model.sendAgree() +// } +// .controlSize(.large) +// .keyboardShortcut(.defaultAction) +// } +// .padding(16) } - .frame(maxWidth: .infinity) - .padding() + .background(Color(white: colorScheme == .light ? 0.0 : 1.0).opacity(0.05)) + .frame(maxWidth: 468.0) + .clipShape(RoundedRectangle(cornerRadius: 8)) } + .frame(maxWidth: .infinity) + .padding() } // MARK: Status else if msg.type == .status { @@ -105,7 +136,7 @@ struct ChatView: View { // MARK: Input Divider Divider() - .padding(.bottom, 0) + .padding([.top, .bottom], 0) // MARK: Input Bar HStack(alignment: .lastTextBaseline, spacing: 0) { @@ -141,52 +172,11 @@ struct ChatView: View { .onTapGesture { focusedField = .chatInput } - - -// .overlay(alignment: .bottom) { -// // MARK: Input Bar -// VStack(alignment: .leading, spacing: 0) { -// -// } -// } - // } - - // VStack(alignment: .center) { - // Spacer() - - - // .onKeyPress(keys: [.return]) { event in - // print(event) - // guard - // event.phase == .down, - // event.key == .return else { - // return .ignored - // } - // - // if event.modifiers.contains(.shift) { - // print("TRYING TO ADD NEW LINE") - // self.input += "\n" - // return .handled - // } - // - // if !self.input.isEmpty { - // model.sendChat(self.input) - // } - // self.input = "" - // - // return .handled - // } - // .onSubmit { - // if !self.input.isEmpty { - // model.sendChat(self.input) - // } - // self.input = "" - // } - } } + .navigationTitle(self.model.serverTitle) + .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") .background(Color(nsColor: .textBackgroundColor)) - // } } } diff --git a/Hotline/macOS/FileImageView.swift b/Hotline/macOS/FileImageView.swift new file mode 100644 index 0000000..867fb45 --- /dev/null +++ b/Hotline/macOS/FileImageView.swift @@ -0,0 +1,56 @@ +import SwiftUI + +enum FileImageViewStatus { + case notloaded + case loading + case loaded +} + +enum FileImageType { + case banner + case file +} + +struct FileImageView: View { + @Environment(Hotline.self) private var model: Hotline + @State var status: FileImageViewStatus = .notloaded + + @MainActor func startLoading() { + if self.status != .notloaded { + return + } + + self.status = .loading + self.model.downloadBanner { success in + if success { + self.status = .loaded + } + else { + self.status = .notloaded + } + } + } + + var body: some View { + HStack(spacing: 0) { + if let img = self.model.bannerImage { + #if os(macOS) + Image(nsImage: img) + .resizable() + .scaledToFit() + #elseif os(iOS) + Image(uiImage: img) + .resizable() + .scaledToFit() + #endif + } + } + .task { + self.startLoading() + } + } +} + +#Preview { + FileImageView() +} diff --git a/Hotline/macOS/NewsView.swift b/Hotline/macOS/NewsView.swift index 33cc03e..45bae68 100644 --- a/Hotline/macOS/NewsView.swift +++ b/Hotline/macOS/NewsView.swift @@ -220,7 +220,7 @@ struct NewsView: View { .background(Color(nsColor: .textBackgroundColor)) } .toolbar { - ToolbarItem(placement:.primaryAction) { + ToolbarItem(placement: .primaryAction) { Button { } label: { @@ -228,13 +228,39 @@ struct NewsView: View { } } - ToolbarItem(placement:.primaryAction) { + ToolbarItem(placement: .primaryAction) { Button { } label: { Image(systemName: "arrowshape.turn.up.left") } } + +// if let bannerImage = model.bannerImage { +// ToolbarItem(placement: .primaryAction) { +//// HStack { +// bannerImage +// .resizable() +// .aspectRatio(contentMode: .fit) +// .clipped() +// .frame(minHeight: 60, alignment: .topLeading +// ) +// .clipped() +// } +// .frame(maxWidth: .infinity) +// .tag(MenuItem(name: "title", image: "", type: .banner)) +// .padding(.bottom, 16) + + // VStack(spacing: 0) { + // bannerImage + // .resizable() + // .aspectRatio(contentMode: .fit) + // .frame(maxWidth: .infinity, minHeight: 60, alignment: .topLeading) + // .clipped() + // } + // .frame(maxWidth: .infinity) +// } +// } } } } diff --git a/Hotline/macOS/ServerView.swift b/Hotline/macOS/ServerView.swift index d858c6e..da5716f 100644 --- a/Hotline/macOS/ServerView.swift +++ b/Hotline/macOS/ServerView.swift @@ -47,9 +47,51 @@ struct ListItemView: View { .scaledToFit() .frame(width: 18, height: 18) Text(title) -// Spacer() } - //.tag(item.tag) + } +} + +struct AgreementView: View { + @Environment(\.dismiss) var dismiss + + let text: String + let disagree: (() -> Void)? + let agree: (() -> Void)? + + 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) + } + .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(maxWidth: .infinity) + .padding(16) + } + .frame(width: 500, height: 500) } } @@ -70,45 +112,51 @@ private func connectionStatusToProgress(status: HotlineClientStatus) -> Double { struct ServerView: View { @Environment(Hotline.self) private var model: Hotline - @State private var selectedCategoryId: MenuItem.ID? @Environment(\.dismiss) var dismiss - let server: Server - + @State private var agreementShown: Bool = false @State private var selection: MenuItem? = ServerView.menuItems.first + + let server: Server + static var menuItems = [ MenuItem(name: "Chat", image: "bubble", type: .chat), 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), +// MenuItem(name: "Tasks", image: "arrow.up.circle", type: .tasks), ] - - -// @State private var selection: String? - var body: some View { NavigationSplitView { List(selection: $selection) { - - HStack { - Text(server.name ?? "") - .fontWeight(.medium) - .lineLimit(2) - .font(.title3) - .multilineTextAlignment(.center) - .padding() - } - .selectionDisabled() - .frame(maxWidth: .infinity, minHeight: 60) - .background(VisualEffectView(material: .titlebar, blendingMode: .withinWindow).cornerRadius(16)) -// .background(.white.opacity(0.2)) - .cornerRadius(10) -// .shadow(color: .black.opacity(0.1), radius: 3, y: 2) - .tag(MenuItem(name: "title", image: "", type: .banner)) - .padding(.bottom, 16) + +// VStack(spacing: 0) { +// bannerImage +// .resizable() +// .aspectRatio(contentMode: .fit) +// .frame(maxWidth: .infinity, minHeight: 60, alignment: .topLeading) +// .clipped() +// } +// .frame(maxWidth: .infinity) +// } +// else { +// HStack { +// Text(server.name ?? "") +// .fontWeight(.medium) +// .lineLimit(2) +// .font(.title3) +// .multilineTextAlignment(.center) +// .padding() +// } +// .selectionDisabled() +// .frame(maxWidth: .infinity, minHeight: 60) +// .background(VisualEffectView(material: .titlebar, blendingMode: .withinWindow).cornerRadius(16)) +// .cornerRadius(10) +// .tag(MenuItem(name: "title", image: "", type: .banner)) +// .padding(.bottom, 16) +// } if model.status != .loggedIn { HStack { @@ -121,17 +169,19 @@ struct ServerView: View { } if model.status == .loggedIn { - ForEach(ServerView.menuItems) { menuItem in - if let minServerVersion = menuItem.serverVersion { - if let v = model.serverVersion, v >= minServerVersion { + Section(model.serverTitle) { + 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) } } - else { - ListItemView(icon: menuItem.image, title: menuItem.name) - .tag(menuItem) - } } if model.users.count > 0 { @@ -171,42 +221,76 @@ struct ServerView: View { switch selection.type { case .banner: EmptyView() - case .progress - : + case .progress: EmptyView() case .chat: ChatView() + .navigationTitle(self.model.serverTitle) + .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") case .news: NewsView() + .navigationTitle(self.model.serverTitle) + .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") case .messageBoard: MessageBoardView() + .navigationTitle(self.model.serverTitle) + .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") case .files: FilesView() + .navigationTitle(self.model.serverTitle) + .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") case .tasks: EmptyView() case .user: if let selectionUserID = selection.userID { MessageView(userID: selectionUserID) + .navigationTitle(self.model.serverTitle) + .navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "") } } } } .navigationTitle("") .onAppear { - Task { - await model.login(server: self.server, login: "", password: "", username: "bolt", iconID: 128) + self.model.login(server: self.server, login: "", password: "", username: "bolt", iconID: 128) { success in + if !success { + print("FAILED LOGIN??") + } + else { + self.model.sendUserInfo(username: "bolt", iconID: 128) + print("GETTING USER LIST????!") + self.model.getUserList() + } } } .onDisappear { - Task { - model.disconnect() - } + self.model.disconnect() } .onChange(of: model.status) { if model.status == .disconnected { dismiss() } } +// .onChange(of: model.agreement) { +// if model.agreement != nil { +// agreementShown = true +// } +// } +// .sheet(isPresented: $agreementShown, onDismiss: { +// if model.status == .disconnected { +// dismiss() +// } +// }, content: { +// if let text = model.agreement { +// AgreementView(text: text, disagree: { +// self.model.disconnect() +// print("DISAGREE") +// }, agree: { +// print("AGREE?") +// }) +//// .frame(minWidth: 300, maxWidth: 500, minHeight: 300) +// } +// }) } } diff --git a/Hotline/macOS/TrackerView.swift b/Hotline/macOS/TrackerView.swift index ca1595d..874bcc2 100644 --- a/Hotline/macOS/TrackerView.swift +++ b/Hotline/macOS/TrackerView.swift @@ -215,10 +215,11 @@ struct TrackerView: View { // @AppStorage("servers", store: .standard) var bookmarks: [TrackerBookmark] = [ - TrackerBookmark(type: .server, name: "Bob Kiwi's House", address: "73.132.92.104"), + TrackerBookmark(type: .server, name: "RetroMac", address: "82.32.130.173"), TrackerBookmark(type: .server, name: "System 7 Today", address: "158.174.146.146"), + TrackerBookmark(type: .server, name: "Bob Kiwi's House", address: "73.132.92.104"), TrackerBookmark(type: .tracker, name: "Featured Servers", address: "hltracker.com"), - TrackerBookmark(type: .tracker, name: "Ubersoft", address: "hotline.ubersoft.org"), + TrackerBookmark(type: .tracker, name: "Agent79", address: "tracked.agent79.org"), TrackerBookmark(type: .tracker, name: "Preterhuman", address: "tracker.preterhuman.net"), // "hltracker.com" |