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:
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()