damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 552402f2b58d8022ef760de76e873e3f1a029225
parent 852609ee30a861caa67ffdc7dc73882897254f15
Author: Joel Klabo <joelklabo@gmail.com>
Date:   Wed,  1 Feb 2023 13:49:32 -0800

Add Relay Detail View

Changelog-Added: Relay Detail View
Closes: #479

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 8++++++++
Mdamus/Nostr/Relay.swift | 10++++++++++
Adamus/Util/NIPURLBuilder.swift | 26++++++++++++++++++++++++++
Adamus/Views/Relays/RelayDetailView.swift | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdamus/Views/Relays/RelayView.swift | 6+++++-
5 files changed, 165 insertions(+), 1 deletion(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -203,6 +203,8 @@ DD597CBD2963D85A00C64D32 /* MarkdownTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */; }; E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; }; E9E4ED0B295867B900DD7078 /* ThreadV2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */; }; + F7908E92298B0F0700AB113A /* RelayDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7908E91298B0F0700AB113A /* RelayDetailView.swift */; }; + F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7908E96298B1FDF00AB113A /* NIPURLBuilder.swift */; }; F7F0BA25297892BD009531F3 /* SwipeToDismiss.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */; }; F7F0BA272978E54D009531F3 /* ParicipantsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F0BA262978E54D009531F3 /* ParicipantsView.swift */; }; /* End PBXBuildFile section */ @@ -486,6 +488,8 @@ DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownTests.swift; sourceTree = "<group>"; }; E990020E2955F837003BBC5A /* EditMetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMetadataView.swift; sourceTree = "<group>"; }; E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadV2View.swift; sourceTree = "<group>"; }; + F7908E91298B0F0700AB113A /* RelayDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayDetailView.swift; sourceTree = "<group>"; }; + F7908E96298B1FDF00AB113A /* NIPURLBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIPURLBuilder.swift; sourceTree = "<group>"; }; F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeToDismiss.swift; sourceTree = "<group>"; }; F7F0BA262978E54D009531F3 /* ParicipantsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParicipantsView.swift; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -721,6 +725,7 @@ 4CF0ABEA29844B2F00D66079 /* AnyCodable */, 4CC7AAE6297EFA7B00430951 /* Zap.swift */, 4C3A1D322960DB0500558C0F /* Markdown.swift */, + F7908E96298B1FDF00AB113A /* NIPURLBuilder.swift */, 4CEE2AF4280B29E600AB5EEF /* TimeAgo.swift */, 4CE4F8CC281352B30009DFBB /* Notifications.swift */, 4C363A8328233689006E126D /* Parser.swift */, @@ -752,6 +757,7 @@ 4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */, 4C06670028FC7C5900038D2A /* RelayView.swift */, 4CAAD8AF29888AD200060CEA /* RelayConfigView.swift */, + F7908E91298B0F0700AB113A /* RelayDetailView.swift */, ); path = Relays; sourceTree = "<group>"; @@ -1160,6 +1166,7 @@ 4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */, 4CC7AAEB297F0AEC00430951 /* BuilderEventView.swift in Sources */, 31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */, + F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */, 4C285C8228385570008A31F1 /* CarouselView.swift in Sources */, 4C3EA67F28FFC01D00C48A62 /* InvoiceView.swift in Sources */, 4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */, @@ -1249,6 +1256,7 @@ E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */, 5C513FBA297F72980072348F /* CustomPicker.swift in Sources */, 4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */, + F7908E92298B0F0700AB113A /* RelayDetailView.swift in Sources */, 4C3A1D332960DB0500558C0F /* Markdown.swift in Sources */, 4CF0ABD42980996B00D66079 /* Report.swift in Sources */, 4C0A3F97280F8E02000448DE /* ThreadView.swift in Sources */, diff --git a/damus/Nostr/Relay.swift b/damus/Nostr/Relay.swift @@ -24,6 +24,16 @@ enum RelayFlags: Int { case broken = 1 } +struct RelayNIP11: Codable { + var name = "No data available" + var description = "No data available" + var pubkey = "No data available" + var contact = "No data available" + var supported_nips: [Int] = [] + var software = "No data available" + var version = "No data available" +} + class Relay: Identifiable { let descriptor: RelayDescriptor let connection: RelayConnection diff --git a/damus/Util/NIPURLBuilder.swift b/damus/Util/NIPURLBuilder.swift @@ -0,0 +1,26 @@ +// +// NIPURLBuilder.swift +// damus +// +// Created by Honk on 2/1/23. +// + +import Foundation + +struct NIPURLBuilder { + static private let baseURL = "https://github.com/nostr-protocol/nips/blob/master/" + static func url(forNIP nip: Int) -> URL? { + let urlString = baseURL + "\(formatNipNumber(nip: nip)).md" + return URL(string: urlString) + } + + static func formatNipNumber(nip: Int) -> String { + let formatted: String + if nip < 10 { + formatted = "0\(nip)" + } else { + formatted = "\(nip)" + } + return formatted + } +} diff --git a/damus/Views/Relays/RelayDetailView.swift b/damus/Views/Relays/RelayDetailView.swift @@ -0,0 +1,116 @@ +// +// RelayDetailView.swift +// damus +// +// Created by Joel Klabo on 2/1/23. +// + +import SwiftUI + +struct RelayDetailView: View { + let state: DamusState + let relay: String + + @State private var errorString: String? + @State private var nip11: RelayNIP11? + + @State var conn_color: Color + + var body: some View { + Group { + if let nip11 { + Form { + Section(NSLocalizedString("Admin", comment: "Label to display relay contact user.")) { + UserView(damus_state: state, pubkey: nip11.pubkey) + } + Section(NSLocalizedString("Relay", comment: "Label to display relay address.")) { + HStack { + Text(relay) + Spacer() + Circle() + .frame(width: 8.0, height: 8.0) + .foregroundColor(conn_color) + } + } + Section(NSLocalizedString("Description", comment: "Label to display relay description.")) { + Text(nip11.description) + } + Section(NSLocalizedString("Contact", comment: "Label to display relay contact information.")) { + Text(nip11.contact) + } + Section(NSLocalizedString("Software", comment: "Label to display relay software.")) { + Text(nip11.software) + } + Section(NSLocalizedString("Version", comment: "Label to display relay software version.")) { + Text(nip11.version) + } + Section(NSLocalizedString("Supported NIPs", comment: "Label to display relay's supported NIPs.")) { + Text(nipsList(nips: nip11.supported_nips)) + } + } + } else if let errorString { + Text(errorString) + .foregroundColor(.red) + .font(.caption) + } else { + ProgressView() + } + } + .navigationTitle(nip11?.name ?? "") + .task { + var urlString = relay.replacingOccurrences(of: "wss://", with: "https://") + urlString = urlString.replacingOccurrences(of: "ws://", with: "http://") + + guard let url = URL(string: urlString) else { + return + } + + var request = URLRequest(url: url) + request.setValue("application/nostr+json", forHTTPHeaderField: "Accept") + + var res: (Data, URLResponse)? = nil + + do { + res = try await URLSession.shared.data(for: request) + } catch { + errorString = error.localizedDescription + return + } + + guard let data = res?.0 else { + errorString = "Relay not responding to metadata request" + return + } + + do { + let nip11 = try JSONDecoder().decode(RelayNIP11.self, from: data) + self.nip11 = nip11 + } catch { + errorString = error.localizedDescription + } + } + } + + private func nipsList(nips: [Int]) -> AttributedString { + var attrString = AttributedString() + let lastNipIndex = nips.count - 1 + for (index, nip) in nips.enumerated() { + if let link = NIPURLBuilder.url(forNIP: nip) { + let nipString = NIPURLBuilder.formatNipNumber(nip: nip) + var nipAttrString = AttributedString(stringLiteral: nipString) + nipAttrString.link = link + attrString = attrString + nipAttrString + if index < lastNipIndex { + attrString = attrString + AttributedString(stringLiteral: ", ") + } + } + } + return attrString + } +} + +struct RelayDetailView_Previews: PreviewProvider { + static var previews: some View { + RelayDetailView(state: test_damus_state(), relay: "wss://nostr.klabo.blog", conn_color: .green) + } +} diff --git a/damus/Views/Relays/RelayView.swift b/damus/Views/Relays/RelayView.swift @@ -34,7 +34,11 @@ struct RelayView: View { Circle() .frame(width: 8.0, height: 8.0) .foregroundColor(conn_color) - Text(relay) + NavigationLink { + RelayDetailView(state: state, relay: relay, conn_color: conn_color) + } label: { + Text(relay) + } } .onReceive(timer) { _ in update_connection_color()