diff options
| author | Dustin Mierau <dustin@mierau.me> | 2023-12-04 14:31:12 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2023-12-04 14:31:12 -0800 |
| commit | b1a176ba3da2c7cf815084f0f8109008fe763809 (patch) | |
| tree | 5bbf52900d5dab9091216cc0f1e5dc84ad69cc9f /Hotline | |
| parent | 471546236b8991f61d26c0e3aa8ee48b83b983af (diff) | |
Starting to get app views displaying data (roughly)
Diffstat (limited to 'Hotline')
| -rw-r--r-- | Hotline/Hotline/HotlineClient.swift | 63 | ||||
| -rw-r--r-- | Hotline/Hotline/HotlineProtocol.swift | 4 | ||||
| -rw-r--r-- | Hotline/HotlineApp.swift | 2 | ||||
| -rw-r--r-- | Hotline/Views/AgreementView.swift | 7 | ||||
| -rw-r--r-- | Hotline/Views/ChatView.swift | 78 | ||||
| -rw-r--r-- | Hotline/Views/FilesView.swift | 32 | ||||
| -rw-r--r-- | Hotline/Views/HotlineState.swift | 24 | ||||
| -rw-r--r-- | Hotline/Views/HotlineView.swift | 11 | ||||
| -rw-r--r-- | Hotline/Views/MessageBoardView.swift | 42 | ||||
| -rw-r--r-- | Hotline/Views/ServerView.swift | 57 | ||||
| -rw-r--r-- | Hotline/Views/TrackerServerView.swift | 13 | ||||
| -rw-r--r-- | Hotline/Views/TrackerView.swift | 85 | ||||
| -rw-r--r-- | Hotline/Views/UserListView.swift | 21 |
13 files changed, 317 insertions, 122 deletions
diff --git a/Hotline/Hotline/HotlineClient.swift b/Hotline/Hotline/HotlineClient.swift index b5ea1d9..de01ae9 100644 --- a/Hotline/Hotline/HotlineClient.swift +++ b/Hotline/Hotline/HotlineClient.swift @@ -9,10 +9,26 @@ enum HotlineClientStatus: Int { case loggedIn } -struct HotlineChat { +struct HotlineChat: Identifiable { + let id = UUID() let message: String - let userID: UInt16? + let username: String let isTopic: Bool + + static let parser = /\s+(.+):\s+(.*)/ + + init(message: String, isTopic: Bool = false) { + self.isTopic = isTopic + + if let match = message.firstMatch(of: HotlineChat.parser) { + self.username = String(match.1) + self.message = String(match.2) + } + else { + self.username = "" + self.message = message + } + } } @Observable @@ -29,8 +45,9 @@ class HotlineClient { var connectionStatus: HotlineClientStatus = .disconnected var agreement: String? var users: [UInt16:HotlineUser] = [:] - var userList: [UInt16] = [] + var userList: [HotlineUser] = [] var chatMessages: [HotlineChat] = [] + var messageBoard: String = "" var userName: String = "bolt" var userIconID: UInt16 = 128 @@ -324,6 +341,19 @@ class HotlineClient { self.sendTransaction(t, callback: callback) } + func sendGetNews(callback: (() -> Void)? = nil) { + let t = HotlineTransaction(type: .getMessages) + self.sendTransaction(t, callback: callback) + } + + func sendGetFileList(path: String? = nil, callback: (() -> Void)? = nil) { + let t = HotlineTransaction(type: .getFileNameList) + if let p = path { +// t.setFieldString(type: .filePath) + } + self.sendTransaction(t, callback: callback) + } + // MARK: - Incoming private func processReply(_ transaction: HotlineTransaction) { @@ -356,11 +386,11 @@ class HotlineClient { case .getUserNameList: print("GOT USER LIST") var newUsers: [UInt16:HotlineUser] = [:] - var newUserList: [UInt16] = [] + var newUserList: [HotlineUser] = [] for u in transaction.getFieldList(type: .userNameWithInfo) { let user = u.getUser() newUsers[user.id] = user - newUserList.append(user.id) + newUserList.append(user) } DispatchQueue.main.async { self.users = newUsers @@ -369,6 +399,13 @@ class HotlineClient { print("HotlineClient got users:\n") print("\(self.userList)\n\n") } + case .getMessages: + print("GOT MESSAGE BOARD") + if let textField = transaction.getField(type: .data), let text = textField.getString() { + DispatchQueue.main.async { + self.messageBoard = text + } + } default: break } @@ -389,16 +426,18 @@ class HotlineClient { // print("HotlineClient: Received reply transaction: \(transaction)") case .chatMessage: + print("HotlineClient: chat \(transaction)") if let chatTextParam = transaction.getField(type: .data), - let chatText = chatTextParam.getString(), - let userNameParam = transaction.getField(type: .userName), - let userName = userNameParam.getString(), - let userIDParam = transaction.getField(type: .userID), - let userID = userIDParam.getUInt16() { - print("HotlineClient: \(userName):\(userID): \(chatText)") + let chatText = chatTextParam.getString() +// let userNameParam = transaction.getField(type: .userName), +// let userName = userNameParam.getString(), +// let userIDParam = transaction.getField(type: .userID), +// let userID = userIDParam.getUInt16() { + { + print("HotlineClient: \(chatText)") DispatchQueue.main.async { - self.chatMessages.append(HotlineChat(message: chatText, userID: userID, isTopic: false)) + self.chatMessages.append(HotlineChat(message: chatText, isTopic: false)) } } case .notifyOfUserChange: diff --git a/Hotline/Hotline/HotlineProtocol.swift b/Hotline/Hotline/HotlineProtocol.swift index 200ac47..20168b0 100644 --- a/Hotline/Hotline/HotlineProtocol.swift +++ b/Hotline/Hotline/HotlineProtocol.swift @@ -285,6 +285,7 @@ enum HotlineTransactionFieldType: UInt16 { case versionNumber = 160 // Integer case communityBannerID = 161 // Integer case serverName = 162 // String + case fileNameWithInfo = 200 // Data { type: 4, creator: 4, file size: 4, reserved: 4, name script: 2, name size: 2, name data: size } // TODO: Add file field types case quotingMessage = 214 // String? case automaticResponse = 215 // String @@ -348,6 +349,9 @@ enum HotlineTransactionType: UInt16 { case downloadInfo = 211 // Server case downloadBanner = 212 case uploadFolder = 213 + case getNewsFile = 294 + case postNews = 295 + case receiveNewsFile = 296 // Server case getUserNameList = 300 case notifyOfUserChange = 301 // Server case notifyOfUserDelete = 302 // Server diff --git a/Hotline/HotlineApp.swift b/Hotline/HotlineApp.swift index 238ca48..d999e89 100644 --- a/Hotline/HotlineApp.swift +++ b/Hotline/HotlineApp.swift @@ -16,6 +16,7 @@ struct HotlineApp: App { // } // }() + @State private var appState = HotlineState() @State private var hotline = HotlineClient() @State private var tracker = HotlineTrackerClient(tracker: HotlineTracker("hltracker.com")) @@ -23,6 +24,7 @@ struct HotlineApp: App { WindowGroup { HotlineView() + .environment(appState) .environment(hotline) .environment(tracker) } diff --git a/Hotline/Views/AgreementView.swift b/Hotline/Views/AgreementView.swift index c61c9d7..39730ce 100644 --- a/Hotline/Views/AgreementView.swift +++ b/Hotline/Views/AgreementView.swift @@ -1,11 +1,13 @@ import SwiftUI struct AgreementView: View { - @Environment(\.dismiss) var dismiss + @Environment(HotlineState.self) private var appState let text: String var body: some View { +// @Bindable var config = appState + VStack(alignment: .leading) { ScrollView { VStack(alignment: .leading) { @@ -18,11 +20,14 @@ struct AgreementView: View { } Button("OK") { print("DONE") + appState.dismissAgreement() } .bold() .padding(EdgeInsets(top: 16, leading: 24, bottom: 16, trailing: 24)) .frame(maxWidth: .infinity) } + .presentationDetents([.fraction(0.6)]) + .presentationDragIndicator(.visible) } } diff --git a/Hotline/Views/ChatView.swift b/Hotline/Views/ChatView.swift index 532a890..6dc7318 100644 --- a/Hotline/Views/ChatView.swift +++ b/Hotline/Views/ChatView.swift @@ -1,55 +1,64 @@ import SwiftUI struct ChatView: View { -// @Binding private var input: String + @Environment(HotlineClient.self) private var hotline + @State var input: String = "" @State private var scrollPos: Int? @State private var contentHeight: CGFloat = 0 var body: some View { VStack(spacing: 0) { - GeometryReader { geometry in - ScrollView(.vertical) { - ScrollViewReader { scrollReader in - VStack(alignment: .leading) { - Spacer() - LazyVStack(alignment: .leading, spacing: 10) { - HStack(alignment: .firstTextBaseline) { - Text("bolt:").bold().fontDesign(.monospaced).frame(minWidth: 60) - Text("hello!").fontDesign(.monospaced).textSelection(.enabled) - } - ForEach(0..<50) { i in - HStack(alignment: .firstTextBaseline) { - Text("mierau:").bold().fontDesign(.monospaced) - Text("g'day to you. what's going on this afternoon?") - .fontDesign(.monospaced) - .textSelection(.enabled) - } - } - Text("").font(.system(size: 0)).id("bottomScroll") - } - .padding() - } - // .frame(width: geometry.size.width) - .frame(minHeight: geometry.size.height) -// .background(Color.red) - .onAppear() { - scrollReader.scrollTo("bottomScroll", anchor: .bottom) - } - // .onChange() { - // scrollReader.scrollTo(10000, anchor: .bottomTrailing) - // } - } + List(hotline.chatMessages) { msg in + if msg.username == "" { + + } + HStack(alignment: .firstTextBaseline) { + Text("\(msg.username):").bold().fontDesign(.monospaced).font(.system(size: 12)) + Text(msg.message) + .fontDesign(.monospaced) + .textSelection(.enabled) + .font(.system(size: 12)) } } + .padding() + +// GeometryReader { geometry in +// ScrollView(.vertical) { +// ScrollViewReader { scrollReader in +// VStack(alignment: .leading) { +// Spacer() +// List(hotline.chatMessages) { msg in +// HStack(alignment: .firstTextBaseline) { +// Text("\(msg.username):").bold().fontDesign(.monospaced) +// Text(msg.message) +// .fontDesign(.monospaced) +// .textSelection(.enabled) +// } +// } +// .padding() +// } +// // .frame(width: geometry.size.width) +// .frame(minHeight: geometry.size.height) +//// .background(Color.red) +// .onAppear() { +//// scrollReader.scrollTo("bottomScroll", anchor: .bottom) +// } +// // .onChange() { +// // scrollReader.scrollTo(10000, anchor: .bottomTrailing) +// // } +// } +// } +// } Divider() HStack(alignment: .top) { Image(systemName: "chevron.right") - TextField("This is a chat topic", text: $input, axis: .vertical) + TextField("", text: $input, axis: .vertical) .lineLimit(1...5) .onSubmit { + hotline.sendChat(message: self.input) // HotlineClient.shared.sendChat(message: self.input) self.input = "" } @@ -60,4 +69,5 @@ struct ChatView: View { #Preview { ChatView() + .environment(HotlineClient()) } diff --git a/Hotline/Views/FilesView.swift b/Hotline/Views/FilesView.swift new file mode 100644 index 0000000..0e1bb91 --- /dev/null +++ b/Hotline/Views/FilesView.swift @@ -0,0 +1,32 @@ +import SwiftUI + +struct FilesView: View { + @Environment(HotlineClient.self) private var hotline + + @State private var fetched = false + + var body: some View { + ScrollView { + VStack(spacing: 0) { + List(hotline.userList) { u in + HStack(alignment: .firstTextBaseline) { + Text(u.name).bold().foregroundStyle(u.isAdmin ? Color.red : Color.black) + } + } + .padding() + } + } + .task { + if !fetched { + hotline.sendGetFileList() { + fetched = true + } + } + } + } +} + +#Preview { + FilesView() + .environment(HotlineClient()) +} diff --git a/Hotline/Views/HotlineState.swift b/Hotline/Views/HotlineState.swift new file mode 100644 index 0000000..9ae4940 --- /dev/null +++ b/Hotline/Views/HotlineState.swift @@ -0,0 +1,24 @@ +import Foundation +import SwiftUI + +@Observable +class HotlineState { + var agreementPresented = false + var trackerPresented = true + + func presentTracker() { + self.trackerPresented = true + } + + func dismissTracker() { + self.trackerPresented = false + } + + func presentAgreement() { + self.agreementPresented = true + } + + func dismissAgreement() { + self.agreementPresented = false + } +} diff --git a/Hotline/Views/HotlineView.swift b/Hotline/Views/HotlineView.swift index 67ef067..fe67f79 100644 --- a/Hotline/Views/HotlineView.swift +++ b/Hotline/Views/HotlineView.swift @@ -1,13 +1,22 @@ import SwiftUI struct HotlineView: View { + @Environment(HotlineState.self) private var appState @Environment(HotlineClient.self) private var hotline @Environment(HotlineTrackerClient.self) private var tracker - @State private var isTrackerVisible = false + @State private var isTrackerVisible = true var body: some View { + @Bindable var config = appState + NavigationStack { + ServerView() + } + .sheet(isPresented: $config.agreementPresented) { + AgreementView(text: hotline.agreement!) + } + .sheet(isPresented: $config.trackerPresented) { TrackerView() } } diff --git a/Hotline/Views/MessageBoardView.swift b/Hotline/Views/MessageBoardView.swift new file mode 100644 index 0000000..e5f1521 --- /dev/null +++ b/Hotline/Views/MessageBoardView.swift @@ -0,0 +1,42 @@ +import SwiftUI + +struct MessageBoardView: View { + @Environment(HotlineState.self) private var appState + @Environment(HotlineClient.self) private var hotline + + @State private var fetched = false + + var body: some View { +// @Bindable var config = appState + + VStack(alignment: .leading) { + ScrollView { + VStack(alignment: .leading) { + Text(hotline.messageBoard) + .fontDesign(.monospaced) + .padding() + .dynamicTypeSize(.small) + .textSelection(.enabled) + } + } + } + .presentationDetents([.fraction(0.6)]) + .presentationDragIndicator(.visible) + .task { + if !fetched { + hotline.sendGetNews() { + fetched = true + } + } + } + .refreshable { + hotline.sendGetNews() + } + } +} + +#Preview { + MessageBoardView() + .environment(HotlineState()) + .environment(HotlineClient()) +} diff --git a/Hotline/Views/ServerView.swift b/Hotline/Views/ServerView.swift index 1610aa7..0dafbce 100644 --- a/Hotline/Views/ServerView.swift +++ b/Hotline/Views/ServerView.swift @@ -1,53 +1,64 @@ import SwiftUI struct ServerView: View { + @Environment(HotlineState.self) private var appState @Environment(HotlineClient.self) private var hotline @Environment(HotlineTrackerClient.self) private var tracker - - @State private var isTrackerVisible = false - + var body: some View { + @Bindable var config = appState + TabView { NavigationView { ChatView() - .navigationTitle("Badmoon") + .navigationTitle(hotline.server?.name ?? "Hotline") + .navigationBarTitleDisplayMode(.inline) .navigationBarItems( leading: Button(action: { - withAnimation { - isTrackerVisible.toggle() - } + appState.presentTracker() }) { - Image(systemName: "line.horizontal.3") // Hamburger icon or similar + Image(systemName: "globe.americas.fill") // Hamburger icon or similar .imageScale(.large) } ) - .toolbarBackground(.visible, for: .navigationBar) - .toolbarBackground(.red, for: .navigationBar) +// .toolbarBackground(.visible, for: .navigationBar) +// .toolbarBackground(.red, for: .navigationBar) } - .navigationBarTitleDisplayMode(.inline) .tabItem { Image(systemName: "message") } - Text("Users") - .tabItem { - Image(systemName: "person.fill") - } + NavigationView { + UserListView() + .navigationTitle("User List") + .navigationBarTitleDisplayMode(.inline) + } + .tabItem { + Image(systemName: "person.fill") + } Text("News") .tabItem { Image(systemName: "newspaper") } - Text("Files") - .tabItem { - Image(systemName: "folder") - } + NavigationView { + MessageBoardView() + .navigationTitle("Message Board") + .navigationBarTitleDisplayMode(.inline) + } + .tabItem { + Image(systemName: "pin") + } - Text("Transfers") - .tabItem { - Image(systemName: "network") - } + NavigationView { + FilesView() + .navigationTitle("Files") + .navigationBarTitleDisplayMode(.inline) + } + .tabItem { + Image(systemName: "folder") + } } // .sheet(isPresented: Binding(get: { hotline.connectionStatus != .loggedIn }, set: { _ in })) { // TrackerView() diff --git a/Hotline/Views/TrackerServerView.swift b/Hotline/Views/TrackerServerView.swift index 5be6f7a..2c0f3e3 100644 --- a/Hotline/Views/TrackerServerView.swift +++ b/Hotline/Views/TrackerServerView.swift @@ -1,11 +1,15 @@ import SwiftUI struct TrackerServerView: View { - @Environment(\.dismiss) var dismiss + @Environment(HotlineState.self) private var appState + @Environment(HotlineClient.self) private var hotline + @Environment(\.dismiss) private var dismiss let server: HotlineServer var body: some View { + @Bindable var config = appState + VStack(alignment: .leading) { HStack { Text("🌎").dynamicTypeSize(.xxxLarge) @@ -20,9 +24,9 @@ struct TrackerServerView: View { HStack(alignment: .center) { Button("Connect") { - print("WHAT", "HELLO", server.address) -// HotlineClient.shared.connect(to: server) - dismiss() + hotline.connect(to: server) + config.dismissTracker() +// dismiss() } .bold() .padding(EdgeInsets(top: 16, leading: 24, bottom: 16, trailing: 24)) @@ -44,4 +48,5 @@ struct TrackerServerView: View { #Preview { TrackerServerView(server: HotlineServer(address: "192.168.1.1", port: 5050, users: 5, name: "Ye Olde Server", description: "This is a server")) + .environment(HotlineClient()) } diff --git a/Hotline/Views/TrackerView.swift b/Hotline/Views/TrackerView.swift index 5d1afe2..edb2330 100644 --- a/Hotline/Views/TrackerView.swift +++ b/Hotline/Views/TrackerView.swift @@ -5,63 +5,54 @@ struct TrackerView: View { // @Environment(\.modelContext) private var modelContext // @Query private var items: [Item] + @Environment(HotlineState.self) private var appState @Environment(HotlineClient.self) private var hotline @Environment(HotlineTrackerClient.self) private var tracker - // @StateObject var tracker = HotlineTrackerClient(address: "hltracker.com") - // @StateObject var client = HotlineClient.shared - @State private var selectedServer: HotlineServer? - @State private var showingAgreement = false - @State private var showingConnectSheet = false - - // @Bindable var trackerTest = tracker var body: some View { - List(selection: $selectedServer) { - ForEach(tracker.servers) { server in - HStack { - Text("🌎") - Text(server.name!).bold() - Spacer() - Text("\(server.users)").opacity(0.6) + @Bindable var config = appState + + NavigationView { + List(selection: $selectedServer) { + ForEach(tracker.servers) { server in + TrackerServerView(server: server) } - .listRowBackground(Color(white: 0.96)) - .listRowInsets(EdgeInsets(top: 0, leading: 16.0, bottom: 0, trailing: 16.0)) - .listRowSeparator(.visible, edges: VerticalEdge.Set.all) - .listRowSeparatorTint(Color(white: 1.0)) - .tag(server) } - } - .background(Color(white: 0.96)) - .listStyle(.plain) - .frame(maxWidth: .infinity) - .task { - tracker.fetch() - } - .sheet(item: $selectedServer) { item in - TrackerServerView(server: item) - } - .sheet(isPresented: Binding(get: { hotline.agreement != nil }, set: { _ in })) { - AgreementView(text: hotline.agreement!) - } - .navigationTitle("Tracker") - .navigationBarTitleDisplayMode(.inline) - .toolbar { - ToolbarItem(placement: .topBarTrailing) { - Image(systemName: "gearshape.fill") + .background(Color(white: 0.96)) + .listStyle(.plain) + .frame(maxWidth: .infinity) + .task { + tracker.fetch() + } +// .sheet(item: $selectedServer) { item in +// TrackerServerView(server: item) +// } + .refreshable { + tracker.fetch() + } + .navigationTitle("Tracker") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button { + config.dismissTracker() + } label: { + Image(systemName: "xmark.circle.fill") + .symbolRenderingMode(.hierarchical) + .foregroundColor(.gray) + } + } + // ToolbarItem(placement: .topBarTrailing) { + // Image(systemName: "camera.fill") + // } + // ToolbarItem(placement: .principal) { + // Text("Username") + // } } - // ToolbarItem(placement: .topBarTrailing) { - // Image(systemName: "camera.fill") - // } - // ToolbarItem(placement: .principal) { - // Text("Username") - // } - } - .refreshable { - tracker.fetch() } - .interactiveDismissDisabled() +// .interactiveDismissDisabled() } } diff --git a/Hotline/Views/UserListView.swift b/Hotline/Views/UserListView.swift new file mode 100644 index 0000000..cbb029d --- /dev/null +++ b/Hotline/Views/UserListView.swift @@ -0,0 +1,21 @@ +import SwiftUI + +struct UserListView: View { + @Environment(HotlineClient.self) private var hotline + + var body: some View { + VStack(spacing: 0) { + List(hotline.userList) { u in + HStack(alignment: .firstTextBaseline) { + Text(u.name).bold().foregroundStyle(u.isAdmin ? Color.red : Color.black) + } + } + .padding() + } + } +} + +#Preview { + ChatView() + .environment(HotlineClient()) +} |