diff options
| author | Dustin Mierau <dustin@mierau.me> | 2023-12-16 09:16:15 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2023-12-16 09:16:15 -0800 |
| commit | 3e4fbdfcab4a4d2435aed27a16131a6ca26d7408 (patch) | |
| tree | a1aec47c2de30074257dec14e3b2615a8b178033 /Hotline/Views | |
| parent | a428e3e28fb851cec65ff27f212c19bce08e5369 (diff) | |
Implemented basic news reading support. Various UI tweaks.
Diffstat (limited to 'Hotline/Views')
| -rw-r--r-- | Hotline/Views/ChatView.swift | 5 | ||||
| -rw-r--r-- | Hotline/Views/FilesView.swift | 2 | ||||
| -rw-r--r-- | Hotline/Views/MessageBoardView.swift | 2 | ||||
| -rw-r--r-- | Hotline/Views/NewsView.swift | 188 | ||||
| -rw-r--r-- | Hotline/Views/TrackerView.swift | 8 | ||||
| -rw-r--r-- | Hotline/Views/UsersView.swift | 2 |
6 files changed, 142 insertions, 65 deletions
diff --git a/Hotline/Views/ChatView.swift b/Hotline/Views/ChatView.swift index 8e5b135..e8c7754 100644 --- a/Hotline/Views/ChatView.swift +++ b/Hotline/Views/ChatView.swift @@ -32,7 +32,7 @@ struct ChatView: View { .opacity(0.75) HStack { Spacer() - Text((model.server?.name ?? "") + " Server Agreement") + Text((model.serverTitle) + " Server Agreement") .font(.caption) .fontWeight(.medium) .opacity(0.4) @@ -78,6 +78,7 @@ struct ChatView: View { } .padding(.bottom, 12) } + .defaultScrollAnchor(.bottom) .onChange(of: model.chat.count) { withAnimation { reader.scrollTo(bottomID, anchor: .bottom) @@ -127,7 +128,7 @@ struct ChatView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .principal) { - Text(model.server?.name ?? "") + Text(model.serverTitle) .font(.headline) } ToolbarItem(placement: .navigationBarLeading) { diff --git a/Hotline/Views/FilesView.swift b/Hotline/Views/FilesView.swift index 5cbf0c9..8ad3837 100644 --- a/Hotline/Views/FilesView.swift +++ b/Hotline/Views/FilesView.swift @@ -116,7 +116,7 @@ struct FilesView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .principal) { - Text(model.server?.name ?? "") + Text(model.serverTitle) .font(.headline) } ToolbarItem(placement: .navigationBarLeading) { diff --git a/Hotline/Views/MessageBoardView.swift b/Hotline/Views/MessageBoardView.swift index 8a1c831..0d3968f 100644 --- a/Hotline/Views/MessageBoardView.swift +++ b/Hotline/Views/MessageBoardView.swift @@ -42,7 +42,7 @@ struct MessageBoardView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .principal) { - Text(model.server?.name ?? "") + Text(model.serverTitle) .font(.headline) } ToolbarItem(placement: .navigationBarLeading) { diff --git a/Hotline/Views/NewsView.swift b/Hotline/Views/NewsView.swift index ad7904e..bd3ae1c 100644 --- a/Hotline/Views/NewsView.swift +++ b/Hotline/Views/NewsView.swift @@ -1,58 +1,142 @@ import SwiftUI +import UniformTypeIdentifiers -struct NewsView: View { + + +struct NewsItemView: View { @Environment(Hotline.self) private var model: Hotline - @Environment(\.colorScheme) var colorScheme + @Environment(NewsItemSelection.self) private var selectedArticle: NewsItemSelection - @State private var fetched = false - @State private var selectedCategory: NewsCategory? = nil - @State private var topListHeight: CGFloat = 200 - @State private var dividerHeight: CGFloat = 30 + let news: NewsInfo - var articleList: some View { - - // Your list content goes here - List { - ForEach(model.news, id: \.self) { category in - DisclosureGroup { - ProgressView(value: 0.4) - .task { - print("EXPANDED?", category.name) -// hotline.sendGetNewsArticles(path: [cat.name]) { -// print("OK") -// } - } - } label: { - Text(category.name) + @State var expanded = false + + var body: some View { + if news.count > 0 { + DisclosureGroup(isExpanded: $expanded) { + ForEach(news.children) { childNews in + NewsItemView(news: childNews) + .environment(self.selectedArticle) + .frame(height: 38) + } + } label: { + HStack { + if news.type == .bundle { + Text(Image(systemName: "tray.2.fill")) + } + else { + Text(Image(systemName: "tray.full.fill")) + } + Text(news.name) .fontWeight(.medium) .lineLimit(1) .truncationMode(.tail) + Spacer() + if news.count > 0 { + Text("\(news.count)") + .foregroundStyle(.secondary) + } + } + } + .onChange(of: expanded) { + if !expanded { + return + } + + Task { + await model.getNewsList(at: news.path) } } } - .scrollBounceBehavior(.basedOnSize) -// .listStyle(.plain) - } - - var readerView: some View { - // Your list content goes here - ScrollView(.vertical) { - HStack(alignment: .top, spacing: 0) { - Text("HELLO") - .multilineTextAlignment(.leading) + else { + HStack { + Text(Image(systemName: "doc.text")) + Text(news.name) + .fontWeight(.medium) + .lineLimit(1) + .truncationMode(.tail) Spacer() + if news.count > 0 { + Text("\(news.count)") + .foregroundStyle(.secondary) + } + } + .onTapGesture { + if news.type == .article { + print("SELECTED", news.name) + selectedArticle.selectedArticle = news + } } - .padding() } - .scrollBounceBehavior(.basedOnSize) - .background(colorScheme == .dark ? Color(white: 0.1) : Color(uiColor: UIColor.systemBackground)) } +} + +@Observable +class NewsItemSelection: Equatable { + var selectedArticle: NewsInfo? = nil + static func == (lhs: NewsItemSelection, rhs: NewsItemSelection) -> Bool { + return lhs.selectedArticle == rhs.selectedArticle + } +} + +struct NewsView: View { + @Environment(Hotline.self) private var model: Hotline + @Environment(\.colorScheme) var colorScheme + + @State private var fetched = false + @State private var selectedCategory: NewsInfo? = nil + @State private var topListHeight: CGFloat = 200 + @State private var dividerHeight: CGFloat = 30 + + @State private var articleSelection = NewsItemSelection() + @State private var articleText = "" +// @State private var selectedArticleID: UInt? + + var articleList: some View { + VStack(spacing: 0) { + if model.news.count == 0 { + Text("No News Available") + .font(.headline) + .opacity(0.3) + } + else { + List(model.news) { category in + NewsItemView(news: category) + .environment(self.articleSelection) + .frame(height: 38) + } + .scrollBounceBehavior(.basedOnSize) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color(uiColor: .systemGroupedBackground)) + + // .listStyle(.plain) + } + var body: some View { NavigationStack { VStack(spacing: 0) { articleList .frame(height: topListHeight) + .frame(minHeight: topListHeight) + .onChange(of: self.articleSelection.selectedArticle) { + self.articleText = "" + if + let article = self.articleSelection.selectedArticle, + let articleFlavor = article.articleFlavors?.first, + let articleID = article.articleID { + Task { + if let articleText = await self.model.getNewsArticle(id: articleID, at: article.path, flavor: articleFlavor) { + self.articleText = articleText + } + } + } +// print("SELECTED ARTICLE", articleSelection.selectedArticle?.name) + } + + // Movable Divider VStack(alignment: .center) { Divider() Spacer() @@ -72,28 +156,31 @@ struct NewsView: View { .onChanged { gesture in let delta = gesture.translation.height topListHeight = max(min(topListHeight + delta, 500), 50) - // bottomListHeight = max(min(bottomListHeight - delta, 400), 0) } ) - readerView + + // Reader View + ScrollView(.vertical) { + HStack(alignment: .top, spacing: 0) { + Text(self.articleText) + .multilineTextAlignment(.leading) + Spacer() + } + .padding() + } + .scrollBounceBehavior(.basedOnSize) + .background(colorScheme == .dark ? Color(white: 0.1) : Color(uiColor: UIColor.systemBackground)) } .task { if !fetched { - let _ = await model.getNewsCategories() + let _ = await model.getNewsList() fetched = true - - // hotline.sendGetNewsArticles(path: ["News"]) { - // print("GOT ARTICLES?") - // } } } - // .refreshable { - // hotline.sendGetNewsCategories() - // } .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .principal) { - Text(model.server?.name ?? "") + Text(model.serverTitle) .font(.headline) } ToolbarItem(placement: .navigationBarLeading) { @@ -106,19 +193,8 @@ struct NewsView: View { .foregroundColor(.secondary) } } -// ToolbarItem(placement: .navigationBarTrailing) { -// Button { -// -// } label: { -// Image(systemName: "square.and.pencil") -// // .symbolRenderingMode(.hierarchical) -// // .foregroundColor(.secondary) -// } -// -// } } } - } } diff --git a/Hotline/Views/TrackerView.swift b/Hotline/Views/TrackerView.swift index acb2069..6204fd2 100644 --- a/Hotline/Views/TrackerView.swift +++ b/Hotline/Views/TrackerView.swift @@ -86,7 +86,7 @@ struct TrackerConnectView: View { ) .cornerRadius(10.0) Button { - let s = Server(name: address, description: nil, address: address, port: Server.defaultPort, users: 0) + let s = Server(name: nil, description: nil, address: address, port: Server.defaultPort, users: 0) server = s connecting = true Task { @@ -200,7 +200,7 @@ struct TrackerView: View { // "tracked.nailbat.com" // "hotline.duckdns.org" // "tracked.agent79.org" - self.servers = await model.getServers(address: "hltracker.com") + self.servers = await model.getServerList(tracker: "hltracker.com") } var body: some View { @@ -267,7 +267,7 @@ struct TrackerView: View { HStack(alignment: .firstTextBaseline) { Image(systemName: "globe.americas.fill").font(.title3) VStack(alignment: .leading) { - Text(server.name).font(.title3).fontWeight(.medium) + Text(server.name ?? server.address).font(.title3).fontWeight(.medium) if shouldDisplayDescription(server: server) { Spacer() Text(server.description!).opacity(0.5).font(.system(size: 16)) @@ -382,7 +382,7 @@ struct TrackerView: View { Task { model.disconnect() - let _ = await model.login(server: Server(name: address, description: nil, address: address, port: port, users: 0), login: login, password: password, username: "bolt", iconID: 128) + let _ = await model.login(server: Server(name: nil, description: nil, address: address, port: port, users: 0), login: login, password: password, username: "bolt", iconID: 128) } // TODO: Find a better way to show login status when trying to connect outside of the Tracker server list. Perhaps this opens the connect sheet prefilled. diff --git a/Hotline/Views/UsersView.swift b/Hotline/Views/UsersView.swift index f923ff4..d1f3318 100644 --- a/Hotline/Views/UsersView.swift +++ b/Hotline/Views/UsersView.swift @@ -17,7 +17,7 @@ struct UsersView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .principal) { - Text(model.server?.name ?? "") + Text(model.serverTitle) .font(.headline) } ToolbarItem(placement: .navigationBarLeading) { |