diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index 9aa17a87..e5fd8ca3 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -395,6 +395,9 @@ 50C3E08A2AA8E3F7006A4BC0 /* AVPlayer+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C3E0892AA8E3F7006A4BC0 /* AVPlayer+Additions.swift */; }; 50DA11262A16A23F00236234 /* Launch.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50DA11252A16A23F00236234 /* Launch.storyboard */; }; 5C0707D12A1ECB38004E7B51 /* DamusLogoGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C0707D02A1ECB38004E7B51 /* DamusLogoGradient.swift */; }; + 5C14C29B2BBBA29C00079FD2 /* RelaySoftwareDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C14C29A2BBBA29C00079FD2 /* RelaySoftwareDetail.swift */; }; + 5C14C29D2BBBA40B00079FD2 /* RelayAdminDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C14C29C2BBBA40B00079FD2 /* RelayAdminDetail.swift */; }; + 5C14C29F2BBBA5C600079FD2 /* RelayNipList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C14C29E2BBBA5C600079FD2 /* RelayNipList.swift */; }; 5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */; }; 5C513FBA297F72980072348F /* CustomPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FB9297F72980072348F /* CustomPicker.swift */; }; 5C513FCC2984ACA60072348F /* QRCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FCB2984ACA60072348F /* QRCodeView.swift */; }; @@ -1316,6 +1319,9 @@ 50C3E0892AA8E3F7006A4BC0 /* AVPlayer+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVPlayer+Additions.swift"; sourceTree = ""; }; 50DA11252A16A23F00236234 /* Launch.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Launch.storyboard; sourceTree = ""; }; 5C0707D02A1ECB38004E7B51 /* DamusLogoGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLogoGradient.swift; sourceTree = ""; }; + 5C14C29A2BBBA29C00079FD2 /* RelaySoftwareDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySoftwareDetail.swift; sourceTree = ""; }; + 5C14C29C2BBBA40B00079FD2 /* RelayAdminDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayAdminDetail.swift; sourceTree = ""; }; + 5C14C29E2BBBA5C600079FD2 /* RelayNipList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayNipList.swift; sourceTree = ""; }; 5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyUserSearchView.swift; sourceTree = ""; }; 5C513FB9297F72980072348F /* CustomPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPicker.swift; sourceTree = ""; }; 5C513FCB2984ACA60072348F /* QRCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeView.swift; sourceTree = ""; }; @@ -2576,6 +2582,9 @@ children = ( 4CE879542996BAB900F758CC /* RelayPaidDetail.swift */, B57B4C632B312BFA00A232C0 /* RelayAuthenticationDetail.swift */, + 5C14C29A2BBBA29C00079FD2 /* RelaySoftwareDetail.swift */, + 5C14C29C2BBBA40B00079FD2 /* RelayAdminDetail.swift */, + 5C14C29E2BBBA5C600079FD2 /* RelayNipList.swift */, ); path = Detail; sourceTree = ""; @@ -3205,6 +3214,7 @@ 4CC7AAEB297F0AEC00430951 /* BuilderEventView.swift in Sources */, E02429952B7E97740088B16C /* CameraController.swift in Sources */, 31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */, + 5C14C29F2BBBA5C600079FD2 /* RelayNipList.swift in Sources */, D7CB5D3E2B116DAD00AD4105 /* NotificationsManager.swift in Sources */, 50A16FFF2AA76A0900DFEC1F /* VideoController.swift in Sources */, F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */, @@ -3359,6 +3369,7 @@ 3CCD1E6A2A874C4E0099A953 /* Nip98HTTPAuth.swift in Sources */, 4C8EC52529D1FA6C0085D9A8 /* DamusColors.swift in Sources */, 3A4647CF2A413ADC00386AD8 /* CondensedProfilePicturesView.swift in Sources */, + 5C14C29B2BBBA29C00079FD2 /* RelaySoftwareDetail.swift in Sources */, D2277EEA2A089BD5006C3807 /* Router.swift in Sources */, 3A90B1812A4EA3AF00000D94 /* UserSearchCache.swift in Sources */, 4C9D6D162B1AA9C6004E5CD9 /* DisplayTabBarNotify.swift in Sources */, @@ -3386,6 +3397,7 @@ 4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */, B533694E2B66D791008A805E /* MutelistManager.swift in Sources */, 4C32B9532A9AD44700DC3548 /* Verifier.swift in Sources */, + 5C14C29D2BBBA40B00079FD2 /* RelayAdminDetail.swift in Sources */, 4C3EA66028FF5E7700C48A62 /* node_id.c in Sources */, 4C687C212A5F7ED00092C550 /* DamusBackground.swift in Sources */, 4CA352A02A76AE80003BB08B /* Notify.swift in Sources */, diff --git a/damus/Assets.xcassets/Colors/Bitcoin.colorset/Contents.json b/damus/Assets.xcassets/Colors/Bitcoin.colorset/Contents.json new file mode 100644 index 00000000..c54954a2 --- /dev/null +++ b/damus/Assets.xcassets/Colors/Bitcoin.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x1A", + "green" : "0x93", + "red" : "0xF7" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/damus/Components/DamusColors.swift b/damus/Components/DamusColors.swift index 1d6e0f64..1ae8e79f 100644 --- a/damus/Components/DamusColors.swift +++ b/damus/Components/DamusColors.swift @@ -24,6 +24,7 @@ class DamusColors { static let purple = Color("DamusPurple") static let deepPurple = Color("DamusDeepPurple") static let blue = Color("DamusBlue") + static let bitcoin = Color("Bitcoin") static let success = Color("DamusSuccessPrimary") static let successSecondary = Color("DamusSuccessSecondary") static let successTertiary = Color("DamusSuccessTertiary") diff --git a/damus/Nostr/Relay.swift b/damus/Nostr/Relay.swift index f19f777f..399faa1e 100644 --- a/damus/Nostr/Relay.swift +++ b/damus/Nostr/Relay.swift @@ -84,6 +84,33 @@ struct Limitations: Codable { } } +struct Admission: Codable { + let amount: Int64 + let unit: String +} + +struct Subscription: Codable { + let amount: Int64 + let unit: String + let period: Int +} + +struct Publication: Codable { + let kinds: [Int] + let amount: Int64 + let unit: String +} + +struct Fees: Codable { + let admission: [Admission]? + let subscription: [Subscription]? + let publication: [Publication]? + + static var empty: Fees { + Fees(admission: nil, subscription: nil, publication: nil) + } +} + struct RelayMetadata: Codable { let name: String? let description: String? @@ -95,6 +122,7 @@ struct RelayMetadata: Codable { let limitation: Limitations? let payments_url: String? let icon: String? + let fees: Fees? var is_paid: Bool { return limitation?.payment_required ?? false diff --git a/damus/Views/Relays/Detail/RelayAdminDetail.swift b/damus/Views/Relays/Detail/RelayAdminDetail.swift new file mode 100644 index 00000000..3d040b15 --- /dev/null +++ b/damus/Views/Relays/Detail/RelayAdminDetail.swift @@ -0,0 +1,64 @@ +// +// RelayAdminDetail.swift +// damus +// +// Created by eric on 4/1/24. +// + +import SwiftUI + +struct RelayAdminDetail: View { + + let state: DamusState + let nip11: RelayMetadata? + + var body: some View { + HStack(spacing: 15) { + VStack(spacing: 10) { + Text("ADMIN") + .font(.caption) + .fontWeight(.heavy) + .foregroundColor(DamusColors.mediumGrey) + if let pubkey = nip11?.pubkey { + ProfilePicView(pubkey: pubkey, size: 40, highlight: .custom(.gray.opacity(0.5), 1), profiles: state.profiles, disable_animation: state.settings.disable_animation) + .padding(.bottom, 5) + .onTapGesture { + state.nav.push(route: Route.ProfileByKey(pubkey: pubkey)) + } + } else { + Image("user-circle") + .resizable() + .frame(width: 50, height: 50) + .foregroundColor(.gray.opacity(0.5)) + } + } + + Divider().frame(width: 1) + + VStack { + Text("CONTACT") + .font(.caption) + .fontWeight(.heavy) + .foregroundColor(DamusColors.mediumGrey) + Image("messages") + .foregroundColor(.gray) + if nip11?.contact == "" { + Text("N/A") + .font(.subheadline) + .foregroundColor(.gray) + } else { + Text(nip11?.contact ?? "N/A") + .font(.subheadline) + .foregroundColor(.gray) + } + } + } + } +} + +struct RelayAdminDetail_Previews: PreviewProvider { + static var previews: some View { + let metadata = RelayMetadata(name: "name", description: "Relay description", pubkey: test_pubkey, contact: "contact@mail.com", supported_nips: [1,2,3], software: "software", version: "version", limitation: Limitations.empty, payments_url: "https://jb55.com", icon: "", fees: Fees.empty) + RelayAdminDetail(state: test_damus_state, nip11: metadata) + } +} diff --git a/damus/Views/Relays/Detail/RelayAuthenticationDetail.swift b/damus/Views/Relays/Detail/RelayAuthenticationDetail.swift index 3e270963..5f1d9513 100644 --- a/damus/Views/Relays/Detail/RelayAuthenticationDetail.swift +++ b/damus/Views/Relays/Detail/RelayAuthenticationDetail.swift @@ -16,12 +16,41 @@ struct RelayAuthenticationDetail: View { EmptyView() case .pending: Text(NSLocalizedString("Pending", comment: "Label to display that authentication to a server is pending.")) + .font(.caption) + .frame(height: 20) + .padding(.horizontal, 10) + .foregroundColor(DamusColors.warning) + .background(DamusColors.warningQuaternary) + .cornerRadius(20) + .overlay( + RoundedRectangle(cornerRadius: 20) + .stroke(DamusColors.warningBorder, lineWidth: 1) + ) case .verified: Text(NSLocalizedString("Authenticated", comment: "Label to display that authentication to a server has succeeded.")) - .foregroundStyle(DamusColors.success) + .font(.caption) + .frame(height: 20) + .padding(.horizontal, 10) + .foregroundColor(DamusColors.success) + .background(DamusColors.successQuaternary) + .cornerRadius(20) + .overlay( + RoundedRectangle(cornerRadius: 20) + .stroke(DamusColors.successBorder, lineWidth: 1) + ) case .error: Text(NSLocalizedString("Error", comment: "Label to display that authentication to a server has failed.")) - .foregroundStyle(DamusColors.danger) + .font(.caption) + .frame(height: 20) + .padding(.horizontal, 10) + .foregroundColor(DamusColors.danger) + .background(DamusColors.dangerQuaternary) + .border(DamusColors.dangerBorder) + .cornerRadius(20) + .overlay( + RoundedRectangle(cornerRadius: 20) + .stroke(DamusColors.dangerBorder, lineWidth: 1) + ) } } } diff --git a/damus/Views/Relays/Detail/RelayNipList.swift b/damus/Views/Relays/Detail/RelayNipList.swift new file mode 100644 index 00000000..2e547c2c --- /dev/null +++ b/damus/Views/Relays/Detail/RelayNipList.swift @@ -0,0 +1,79 @@ +// +// RelayNipList.swift +// damus +// +// Created by eric on 4/1/24. +// + +import SwiftUI + +struct NIPNumber: View { + let character: String + + var body: some View { + NIPIcon { + Text(verbatim: character) + .font(.title3.bold()) + .mask(Text(verbatim: character) + .font(.title3.bold())) + } + } +} + +struct NIPIcon: View { + let content: Content + + init(@ViewBuilder content: () -> Content) { + self.content = content() + } + + var body: some View { + ZStack { + Circle() + .fill(DamusColors.neutral3) + .frame(width: 40, height: 40) + + content + .foregroundStyle(DamusColors.mediumGrey) + } + } +} + +struct RelayNipList: View { + + let nips: [Int] + @Environment(\.openURL) var openURL + + var body: some View { + VStack(alignment: .leading, spacing: 10) { + + Text(NSLocalizedString("Supported NIPs", comment: "Label to display relay's supported NIPs.")) + .font(.callout) + .fontWeight(.bold) + .foregroundColor(DamusColors.mediumGrey) + + ScrollView(.horizontal) { + HStack { + ForEach(nips, id:\.self) { nip in + if let link = NIPURLBuilder.url(forNIP: nip) { + let nipString = NIPURLBuilder.formatNipNumber(nip: nip) + Button(action: { + openURL(link) + }) { + NIPNumber(character: "\(nipString)") + } + } + } + } + } + .padding(.bottom) + .scrollIndicators(.hidden) + } + } +} + +struct RelayNipList_Previews: PreviewProvider { + static var previews: some View { + RelayNipList(nips: [0, 1, 2, 3, 4, 11, 15, 50]) + } +} diff --git a/damus/Views/Relays/Detail/RelayPaidDetail.swift b/damus/Views/Relays/Detail/RelayPaidDetail.swift index 041b4c8a..f89344f2 100644 --- a/damus/Views/Relays/Detail/RelayPaidDetail.swift +++ b/damus/Views/Relays/Detail/RelayPaidDetail.swift @@ -9,18 +9,78 @@ import SwiftUI struct RelayPaidDetail: View { let payments_url: String? - + var fees: Fees? = nil @Environment(\.openURL) var openURL - var body: some View { + func timeString(time: Int) -> String { + let formatter = DateComponentsFormatter() + formatter.allowedUnits = [.year, .month, .day, .hour, .minute, .second] + formatter.unitsStyle = .full + let formattedString = formatter.string(from: TimeInterval(time)) ?? "" + return formattedString + } + + func Amount(unit: String, amount: Int64) -> some View { HStack { - RelayType(is_paid: true) - if let url = payments_url.flatMap({ URL(string: $0) }) { - Button(action: { - openURL(url) - }, label: { - Text(verbatim: "\(url)") - }) + if unit == "msats" { + Text("\(format_msats(amount))") + .font(.system(size: 13, weight: .heavy)) + .foregroundColor(DamusColors.white) + } else { + Text("\(amount) \(unit)") + .font(.system(size: 13, weight: .heavy)) + .foregroundColor(DamusColors.white) + } + } + } + + var body: some View { + HStack(spacing: 0) { + ZStack(alignment: .leading) { + if let url = payments_url.flatMap({ URL(string: $0) }) { + RelayType(is_paid: true) + .zIndex(1) + + Button(action: { + openURL(url) + }, label: { + if let admission = fees?.admission { + if !admission.isEmpty { + Amount(unit: admission[0].unit, amount: admission[0].amount) + } else { + Text(verbatim: "Paid Relay") + .font(.system(size: 13, weight: .heavy)) + .foregroundColor(DamusColors.white) + } + } else if let subscription = fees?.subscription { + if !subscription.isEmpty { + Amount(unit: subscription[0].unit, amount: subscription[0].amount) + Text("/ \(timeString(time: subscription[0].period))") + .font(.system(size: 13, weight: .heavy)) + .foregroundColor(DamusColors.white) + } + } else if let publication = fees?.publication { + if !publication.isEmpty { + Amount(unit: publication[0].unit, amount: publication[0].amount) + Text("/ event") + .font(.system(size: 13, weight: .heavy)) + .foregroundColor(DamusColors.white) + } + } else { + Text(verbatim: "Paid Relay") + .font(.system(size: 13, weight: .heavy)) + .foregroundColor(DamusColors.white) + } + }) + .padding(EdgeInsets(top: 3, leading: 25, bottom: 3, trailing: 10)) + .background(DamusColors.bitcoin.opacity(0.7)) + .cornerRadius(15) + .overlay( + RoundedRectangle(cornerRadius: 20) + .stroke(DamusColors.warningBorder, lineWidth: 1) + ) + .padding(.leading, 1) + } } } } @@ -28,6 +88,10 @@ struct RelayPaidDetail: View { struct RelayPaidDetail_Previews: PreviewProvider { static var previews: some View { - RelayPaidDetail(payments_url: "https://jb55.com") + let admission = Admission(amount: 1000000, unit: "msats") + let sub = Subscription(amount: 5000000, unit: "msats", period: 2592000) + let pub = Publication(kinds: [1, 4], amount: 100, unit: "msats") + let fees = Fees(admission: [admission], subscription: [sub], publication: [pub]) + RelayPaidDetail(payments_url: "https://jb55.com", fees: fees) } } diff --git a/damus/Views/Relays/Detail/RelaySoftwareDetail.swift b/damus/Views/Relays/Detail/RelaySoftwareDetail.swift new file mode 100644 index 00000000..5168da4e --- /dev/null +++ b/damus/Views/Relays/Detail/RelaySoftwareDetail.swift @@ -0,0 +1,57 @@ +// +// RelaySoftwareDetail.swift +// damus +// +// Created by eric on 4/1/24. +// + +import SwiftUI + +struct RelaySoftwareDetail: View { + + let nip11: RelayMetadata? + + var body: some View { + HStack(spacing: 15) { + VStack { + Text("SOFTWARE") + .font(.caption) + .fontWeight(.heavy) + .foregroundColor(DamusColors.mediumGrey) + + Image("code") + .foregroundColor(.gray) + + let software = nip11?.software + let softwareSeparated = software?.components(separatedBy: "/") + let softwareShortened = softwareSeparated?.last + Text(softwareShortened ?? "N/A") + .font(.subheadline) + .foregroundColor(.gray) + } + + Divider().frame(width: 1) + + VStack { + Text("VERSION") + .font(.caption) + .fontWeight(.heavy) + .foregroundColor(DamusColors.mediumGrey) + + Image("branches") + .foregroundColor(.gray) + + Text(nip11?.version ?? "N/A") + .font(.subheadline) + .foregroundColor(.gray) + } + } + } +} + +struct RelaySoftwareDetail_Previews: PreviewProvider { + static var previews: some View { + let metadata = RelayMetadata(name: "name", description: "desc", pubkey: test_pubkey, contact: "contact", supported_nips: [1,2,3], software: "git+https://github.com/hoytech/strfry.git", version: "0.9.6-26-gc0dec7c", limitation: Limitations.empty, payments_url: "https://jb55.com", icon: "", fees: Fees.empty) + RelaySoftwareDetail(nip11: metadata) + } +} diff --git a/damus/Views/Relays/RelayDetailView.swift b/damus/Views/Relays/RelayDetailView.swift index b844425e..50d93c57 100644 --- a/damus/Views/Relays/RelayDetailView.swift +++ b/damus/Views/Relays/RelayDetailView.swift @@ -32,14 +32,6 @@ struct RelayDetailView: View { } return false } - - func FieldText(_ str: String?) -> some View { - if let s = str { - return Text(verbatim: s) - } else { - return Text("No data available", comment: "Text indicating that there is no data available to show for specific metadata about a relay server.") - } - } func RemoveRelayButton(_ keypair: FullKeypair) -> some View { Button(action: { @@ -60,104 +52,139 @@ struct RelayDetailView: View { } dismiss() }) { - Text("Disconnect From Relay", comment: "Button to disconnect from the relay.") + HStack { + Text("Disconnect", comment: "Button to disconnect from the relay.") + .fontWeight(.semibold) + } + .frame(minWidth: 300, maxWidth: .infinity, alignment: .center) + } + .buttonStyle(NeutralButtonShape.rounded.style) + } + + func ConnectRelayButton(_ keypair: FullKeypair) -> some View { + Button(action: { + guard let ev_before_add = state.contacts.event else { + return + } + guard let ev_after_add = add_relay(ev: ev_before_add, keypair: keypair, current_relays: state.pool.our_descriptors, relay: relay, info: .rw) else { + return + } + process_contact_event(state: state, ev: ev_after_add) + state.postbox.send(ev_after_add) + + if let relay_metadata = make_relay_metadata(relays: state.pool.our_descriptors, keypair: keypair) { + state.postbox.send(relay_metadata) + } + dismiss() + }) { + HStack { + Text("Connect", comment: "Button to connect to the relay.") + .fontWeight(.semibold) + } + .frame(minWidth: 300, maxWidth: .infinity, alignment: .center) + } + .buttonStyle(NeutralButtonShape.rounded.style) + } + + var RelayInfo: some View { + ScrollView(.horizontal) { + Group { + HStack(spacing: 15) { + + RelayAdminDetail(state: state, nip11: nip11) + + Divider().frame(width: 1) + + RelaySoftwareDetail(nip11: nip11) + + } + } + } + .scrollIndicators(.hidden) + } + + var RelayHeader: some View { + HStack(alignment: .top, spacing: 15) { + RelayPicView(relay: relay, icon: nip11?.icon, size: 90, highlight: .none, disable_animation: false) + + VStack(alignment: .leading) { + Text(nip11?.name ?? relay.absoluteString) + .font(.title) + .fontWeight(.bold) + .lineLimit(1) + + Text(relay.absoluteString) + .font(.headline) + .fontWeight(.regular) + .foregroundColor(.gray) + + HStack { + if nip11?.is_paid ?? false { + RelayPaidDetail(payments_url: nip11?.payments_url, fees: nip11?.fees) + } + + if let authentication_state: RelayAuthenticationState = relay_object?.authentication_state, + authentication_state != .none { + RelayAuthenticationDetail(state: authentication_state) + } + } + } } } + var body: some View { NavigationView { - ZStack { - Group { - Form { + Group { + ScrollView { + Divider() + VStack(alignment: .leading, spacing: 10) { + + RelayHeader + + Divider() + + Text("Description") + .font(.subheadline) + .foregroundColor(DamusColors.mediumGrey) + + Text(nip11?.description ?? "N/A") + .font(.subheadline) + + Divider() + + RelayInfo + + Divider() + + if let nip11 { + if let nips = nip11.supported_nips, nips.count > 0 { + RelayNipList(nips: nips) + Divider() + } + } + if let keypair = state.keypair.to_full() { if check_connection() { RemoveRelayButton(keypair) + .padding(.top) } else { - Button(action: { - guard let ev_before_add = state.contacts.event else { - return - } - guard let ev_after_add = add_relay(ev: ev_before_add, keypair: keypair, current_relays: state.pool.our_descriptors, relay: relay, info: .rw) else { - return - } - process_contact_event(state: state, ev: ev_after_add) - state.postbox.send(ev_after_add) - - if let relay_metadata = make_relay_metadata(relays: state.pool.our_descriptors, keypair: keypair) { - state.postbox.send(relay_metadata) - } - dismiss() - }) { - Text("Connect To Relay", comment: "Button to connect to the relay.") - } - } - } - - if let authentication_state: RelayAuthenticationState = relay_object?.authentication_state, - authentication_state != .none { - Section(NSLocalizedString("Authentication", comment: "Header label to display authentication details for a given relay.")) { - RelayAuthenticationDetail(state: authentication_state) - } - } - - if let pubkey = nip11?.pubkey { - Section(NSLocalizedString("Admin", comment: "Label to display relay contact user.")) { - UserViewRow(damus_state: state, pubkey: pubkey) - .onTapGesture { - state.nav.push(route: Route.ProfileByKey(pubkey: pubkey)) - } - } - } - - if let relay_connection { - Section(NSLocalizedString("Relay", comment: "Label to display relay address.")) { - HStack { - Text(relay.absoluteString) - Spacer() - RelayStatusView(connection: relay_connection) - } - } - } - - if let nip11 { - if nip11.is_paid { - Section(content: { - RelayPaidDetail(payments_url: nip11.payments_url) - }, header: { - Text("Paid Relay", comment: "Section header that indicates the relay server requires payment.") - }, footer: { - Text("This is a paid relay, you must pay for notes to be accepted.", comment: "Footer description that explains that the relay server requires payment to post.") - }) - } - - Section(NSLocalizedString("Description", comment: "Label to display relay description.")) { - FieldText(nip11.description) - } - Section(NSLocalizedString("Contact", comment: "Label to display relay contact information.")) { - FieldText(nip11.contact) - } - Section(NSLocalizedString("Software", comment: "Label to display relay software.")) { - FieldText(nip11.software) - } - Section(NSLocalizedString("Version", comment: "Label to display relay software version.")) { - FieldText(nip11.version) - } - if let nips = nip11.supported_nips, nips.count > 0 { - Section(NSLocalizedString("Supported NIPs", comment: "Label to display relay's supported NIPs.")) { - Text(nipsList(nips: nips)) - } + ConnectRelayButton(keypair) + .padding(.top) } } if state.settings.developer_mode { - Section(NSLocalizedString("Log", comment: "Label to display developer mode logs.")) { - Text(log.contents ?? NSLocalizedString("No logs to display", comment: "Label to indicate that there are no developer mode logs available to be displayed on the screen")) - .font(.system(size: 13)) - .lineLimit(nil) - .fixedSize(horizontal: false, vertical: true) - } + Text("Relay Logs") + .padding(.top) + Divider() + Text(log.contents ?? NSLocalizedString("No logs to display", comment: "Label to indicate that there are no developer mode logs available to be displayed on the screen")) + .font(.system(size: 13)) + .lineLimit(nil) + .fixedSize(horizontal: false, vertical: true) } } + .padding(.horizontal) } } } @@ -169,23 +196,11 @@ struct RelayDetailView: View { .navigationBarBackButtonHidden(true) .navigationBarItems(leading: BackNav()) .ignoresSafeArea(.all) - } - - 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: ", ") - } + .toolbar { + if let relay_connection { + RelayStatusView(connection: relay_connection) } } - return attrString } private var relay_object: Relay? { @@ -199,7 +214,11 @@ struct RelayDetailView: View { struct RelayDetailView_Previews: PreviewProvider { static var previews: some View { - let metadata = RelayMetadata(name: "name", description: "desc", pubkey: test_pubkey, contact: "contact", supported_nips: [1,2,3], software: "software", version: "version", limitation: Limitations.empty, payments_url: "https://jb55.com", icon: "") + let admission = Admission(amount: 1000000, unit: "msats") + let sub = Subscription(amount: 5000000, unit: "msats", period: 2592000) + let pub = Publication(kinds: [4], amount: 100, unit: "msats") + let fees = Fees(admission: [admission], subscription: [sub], publication: [pub]) + let metadata = RelayMetadata(name: "name", description: "Relay description", pubkey: test_pubkey, contact: "contact@mail.com", supported_nips: [1,2,3], software: "software", version: "version", limitation: Limitations.empty, payments_url: "https://jb55.com", icon: "", fees: fees) RelayDetailView(state: test_damus_state, relay: RelayURL("wss://relay.damus.io")!, nip11: metadata) } }