aboutsummaryrefslogtreecommitdiff
path: root/Hotline/macOS
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2023-12-22 17:37:13 -0800
committerDustin Mierau <dustin@mierau.me>2023-12-22 17:37:13 -0800
commit4ddc0699afedae39fa27e134bec05330426f2120 (patch)
treece0936e7c537ef527c6472b746b8ef16e471c912 /Hotline/macOS
parent3d26737cccd57fcbb5289874363f030ecef77573 (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.swift104
-rw-r--r--Hotline/macOS/FileImageView.swift56
-rw-r--r--Hotline/macOS/NewsView.swift30
-rw-r--r--Hotline/macOS/ServerView.swift166
-rw-r--r--Hotline/macOS/TrackerView.swift5
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"