mirror of
git://jb55.com/damus
synced 2024-09-30 00:40:45 +00:00
ux: Relay Detail Redesign
This patch redesigns the relay detail view. The first step needed to further improve how relays are viewed. In addition, Fees are added to the relay metadata to present to the user the admission, subscription, or publication fees a relay may have. There are various changes made, but mainly several relay details are moved outside of the main RelayDetail view for easier tracking and updates. With this design we will be able to add ratings and relay previews, as this patch is large enough I will submit that improvement in the future. iPhone 15 Pro Max (17.3.1) Dark Mode: https://i.nostr.build/VwVvq.png https://i.nostr.build/KGO0v.png iPhone SE (3rd generation) (16.4) Light Mode: https://i.nostr.build/M5V26.png https://i.nostr.build/gZKw3.png Changelog-Added: Relay fees metadata Changelog-Changed: Relay detail design Signed-off-by: ericholguin <ericholguin@apache.org> Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
parent
faec79d45d
commit
5492d9f499
@ -395,6 +395,9 @@
|
|||||||
50C3E08A2AA8E3F7006A4BC0 /* AVPlayer+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C3E0892AA8E3F7006A4BC0 /* AVPlayer+Additions.swift */; };
|
50C3E08A2AA8E3F7006A4BC0 /* AVPlayer+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50C3E0892AA8E3F7006A4BC0 /* AVPlayer+Additions.swift */; };
|
||||||
50DA11262A16A23F00236234 /* Launch.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50DA11252A16A23F00236234 /* Launch.storyboard */; };
|
50DA11262A16A23F00236234 /* Launch.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50DA11252A16A23F00236234 /* Launch.storyboard */; };
|
||||||
5C0707D12A1ECB38004E7B51 /* DamusLogoGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C0707D02A1ECB38004E7B51 /* DamusLogoGradient.swift */; };
|
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 */; };
|
5C42E78C29DB76D90086AAC1 /* EmptyUserSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */; };
|
||||||
5C513FBA297F72980072348F /* CustomPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FB9297F72980072348F /* CustomPicker.swift */; };
|
5C513FBA297F72980072348F /* CustomPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FB9297F72980072348F /* CustomPicker.swift */; };
|
||||||
5C513FCC2984ACA60072348F /* QRCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FCB2984ACA60072348F /* QRCodeView.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 = "<group>"; };
|
50C3E0892AA8E3F7006A4BC0 /* AVPlayer+Additions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVPlayer+Additions.swift"; sourceTree = "<group>"; };
|
||||||
50DA11252A16A23F00236234 /* Launch.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Launch.storyboard; sourceTree = "<group>"; };
|
50DA11252A16A23F00236234 /* Launch.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Launch.storyboard; sourceTree = "<group>"; };
|
||||||
5C0707D02A1ECB38004E7B51 /* DamusLogoGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLogoGradient.swift; sourceTree = "<group>"; };
|
5C0707D02A1ECB38004E7B51 /* DamusLogoGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusLogoGradient.swift; sourceTree = "<group>"; };
|
||||||
|
5C14C29A2BBBA29C00079FD2 /* RelaySoftwareDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySoftwareDetail.swift; sourceTree = "<group>"; };
|
||||||
|
5C14C29C2BBBA40B00079FD2 /* RelayAdminDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayAdminDetail.swift; sourceTree = "<group>"; };
|
||||||
|
5C14C29E2BBBA5C600079FD2 /* RelayNipList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayNipList.swift; sourceTree = "<group>"; };
|
||||||
5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyUserSearchView.swift; sourceTree = "<group>"; };
|
5C42E78B29DB76D90086AAC1 /* EmptyUserSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyUserSearchView.swift; sourceTree = "<group>"; };
|
||||||
5C513FB9297F72980072348F /* CustomPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPicker.swift; sourceTree = "<group>"; };
|
5C513FB9297F72980072348F /* CustomPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPicker.swift; sourceTree = "<group>"; };
|
||||||
5C513FCB2984ACA60072348F /* QRCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeView.swift; sourceTree = "<group>"; };
|
5C513FCB2984ACA60072348F /* QRCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeView.swift; sourceTree = "<group>"; };
|
||||||
@ -2576,6 +2582,9 @@
|
|||||||
children = (
|
children = (
|
||||||
4CE879542996BAB900F758CC /* RelayPaidDetail.swift */,
|
4CE879542996BAB900F758CC /* RelayPaidDetail.swift */,
|
||||||
B57B4C632B312BFA00A232C0 /* RelayAuthenticationDetail.swift */,
|
B57B4C632B312BFA00A232C0 /* RelayAuthenticationDetail.swift */,
|
||||||
|
5C14C29A2BBBA29C00079FD2 /* RelaySoftwareDetail.swift */,
|
||||||
|
5C14C29C2BBBA40B00079FD2 /* RelayAdminDetail.swift */,
|
||||||
|
5C14C29E2BBBA5C600079FD2 /* RelayNipList.swift */,
|
||||||
);
|
);
|
||||||
path = Detail;
|
path = Detail;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -3205,6 +3214,7 @@
|
|||||||
4CC7AAEB297F0AEC00430951 /* BuilderEventView.swift in Sources */,
|
4CC7AAEB297F0AEC00430951 /* BuilderEventView.swift in Sources */,
|
||||||
E02429952B7E97740088B16C /* CameraController.swift in Sources */,
|
E02429952B7E97740088B16C /* CameraController.swift in Sources */,
|
||||||
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */,
|
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */,
|
||||||
|
5C14C29F2BBBA5C600079FD2 /* RelayNipList.swift in Sources */,
|
||||||
D7CB5D3E2B116DAD00AD4105 /* NotificationsManager.swift in Sources */,
|
D7CB5D3E2B116DAD00AD4105 /* NotificationsManager.swift in Sources */,
|
||||||
50A16FFF2AA76A0900DFEC1F /* VideoController.swift in Sources */,
|
50A16FFF2AA76A0900DFEC1F /* VideoController.swift in Sources */,
|
||||||
F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */,
|
F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */,
|
||||||
@ -3359,6 +3369,7 @@
|
|||||||
3CCD1E6A2A874C4E0099A953 /* Nip98HTTPAuth.swift in Sources */,
|
3CCD1E6A2A874C4E0099A953 /* Nip98HTTPAuth.swift in Sources */,
|
||||||
4C8EC52529D1FA6C0085D9A8 /* DamusColors.swift in Sources */,
|
4C8EC52529D1FA6C0085D9A8 /* DamusColors.swift in Sources */,
|
||||||
3A4647CF2A413ADC00386AD8 /* CondensedProfilePicturesView.swift in Sources */,
|
3A4647CF2A413ADC00386AD8 /* CondensedProfilePicturesView.swift in Sources */,
|
||||||
|
5C14C29B2BBBA29C00079FD2 /* RelaySoftwareDetail.swift in Sources */,
|
||||||
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */,
|
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */,
|
||||||
3A90B1812A4EA3AF00000D94 /* UserSearchCache.swift in Sources */,
|
3A90B1812A4EA3AF00000D94 /* UserSearchCache.swift in Sources */,
|
||||||
4C9D6D162B1AA9C6004E5CD9 /* DisplayTabBarNotify.swift in Sources */,
|
4C9D6D162B1AA9C6004E5CD9 /* DisplayTabBarNotify.swift in Sources */,
|
||||||
@ -3386,6 +3397,7 @@
|
|||||||
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */,
|
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */,
|
||||||
B533694E2B66D791008A805E /* MutelistManager.swift in Sources */,
|
B533694E2B66D791008A805E /* MutelistManager.swift in Sources */,
|
||||||
4C32B9532A9AD44700DC3548 /* Verifier.swift in Sources */,
|
4C32B9532A9AD44700DC3548 /* Verifier.swift in Sources */,
|
||||||
|
5C14C29D2BBBA40B00079FD2 /* RelayAdminDetail.swift in Sources */,
|
||||||
4C3EA66028FF5E7700C48A62 /* node_id.c in Sources */,
|
4C3EA66028FF5E7700C48A62 /* node_id.c in Sources */,
|
||||||
4C687C212A5F7ED00092C550 /* DamusBackground.swift in Sources */,
|
4C687C212A5F7ED00092C550 /* DamusBackground.swift in Sources */,
|
||||||
4CA352A02A76AE80003BB08B /* Notify.swift in Sources */,
|
4CA352A02A76AE80003BB08B /* Notify.swift in Sources */,
|
||||||
|
20
damus/Assets.xcassets/Colors/Bitcoin.colorset/Contents.json
Normal file
20
damus/Assets.xcassets/Colors/Bitcoin.colorset/Contents.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ class DamusColors {
|
|||||||
static let purple = Color("DamusPurple")
|
static let purple = Color("DamusPurple")
|
||||||
static let deepPurple = Color("DamusDeepPurple")
|
static let deepPurple = Color("DamusDeepPurple")
|
||||||
static let blue = Color("DamusBlue")
|
static let blue = Color("DamusBlue")
|
||||||
|
static let bitcoin = Color("Bitcoin")
|
||||||
static let success = Color("DamusSuccessPrimary")
|
static let success = Color("DamusSuccessPrimary")
|
||||||
static let successSecondary = Color("DamusSuccessSecondary")
|
static let successSecondary = Color("DamusSuccessSecondary")
|
||||||
static let successTertiary = Color("DamusSuccessTertiary")
|
static let successTertiary = Color("DamusSuccessTertiary")
|
||||||
|
@ -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 {
|
struct RelayMetadata: Codable {
|
||||||
let name: String?
|
let name: String?
|
||||||
let description: String?
|
let description: String?
|
||||||
@ -95,6 +122,7 @@ struct RelayMetadata: Codable {
|
|||||||
let limitation: Limitations?
|
let limitation: Limitations?
|
||||||
let payments_url: String?
|
let payments_url: String?
|
||||||
let icon: String?
|
let icon: String?
|
||||||
|
let fees: Fees?
|
||||||
|
|
||||||
var is_paid: Bool {
|
var is_paid: Bool {
|
||||||
return limitation?.payment_required ?? false
|
return limitation?.payment_required ?? false
|
||||||
|
64
damus/Views/Relays/Detail/RelayAdminDetail.swift
Normal file
64
damus/Views/Relays/Detail/RelayAdminDetail.swift
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -16,12 +16,41 @@ struct RelayAuthenticationDetail: View {
|
|||||||
EmptyView()
|
EmptyView()
|
||||||
case .pending:
|
case .pending:
|
||||||
Text(NSLocalizedString("Pending", comment: "Label to display that authentication to a server is 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:
|
case .verified:
|
||||||
Text(NSLocalizedString("Authenticated", comment: "Label to display that authentication to a server has succeeded."))
|
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:
|
case .error:
|
||||||
Text(NSLocalizedString("Error", comment: "Label to display that authentication to a server has failed."))
|
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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
79
damus/Views/Relays/Detail/RelayNipList.swift
Normal file
79
damus/Views/Relays/Detail/RelayNipList.swift
Normal file
@ -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<Content: View>: 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])
|
||||||
|
}
|
||||||
|
}
|
@ -9,18 +9,78 @@ import SwiftUI
|
|||||||
|
|
||||||
struct RelayPaidDetail: View {
|
struct RelayPaidDetail: View {
|
||||||
let payments_url: String?
|
let payments_url: String?
|
||||||
|
var fees: Fees? = nil
|
||||||
@Environment(\.openURL) var openURL
|
@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 {
|
HStack {
|
||||||
RelayType(is_paid: true)
|
if unit == "msats" {
|
||||||
if let url = payments_url.flatMap({ URL(string: $0) }) {
|
Text("\(format_msats(amount))")
|
||||||
Button(action: {
|
.font(.system(size: 13, weight: .heavy))
|
||||||
openURL(url)
|
.foregroundColor(DamusColors.white)
|
||||||
}, label: {
|
} else {
|
||||||
Text(verbatim: "\(url)")
|
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 {
|
struct RelayPaidDetail_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
damus/Views/Relays/Detail/RelaySoftwareDetail.swift
Normal file
57
damus/Views/Relays/Detail/RelaySoftwareDetail.swift
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -33,14 +33,6 @@ struct RelayDetailView: View {
|
|||||||
return false
|
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 {
|
func RemoveRelayButton(_ keypair: FullKeypair) -> some View {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
guard let ev = state.contacts.event else {
|
guard let ev = state.contacts.event else {
|
||||||
@ -60,104 +52,139 @@ struct RelayDetailView: View {
|
|||||||
}
|
}
|
||||||
dismiss()
|
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 {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
ZStack {
|
Group {
|
||||||
Group {
|
ScrollView {
|
||||||
Form {
|
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 let keypair = state.keypair.to_full() {
|
||||||
if check_connection() {
|
if check_connection() {
|
||||||
RemoveRelayButton(keypair)
|
RemoveRelayButton(keypair)
|
||||||
|
.padding(.top)
|
||||||
} else {
|
} else {
|
||||||
Button(action: {
|
ConnectRelayButton(keypair)
|
||||||
guard let ev_before_add = state.contacts.event else {
|
.padding(.top)
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.settings.developer_mode {
|
if state.settings.developer_mode {
|
||||||
Section(NSLocalizedString("Log", comment: "Label to display developer mode logs.")) {
|
Text("Relay 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"))
|
.padding(.top)
|
||||||
.font(.system(size: 13))
|
Divider()
|
||||||
.lineLimit(nil)
|
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"))
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.font(.system(size: 13))
|
||||||
}
|
.lineLimit(nil)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,23 +196,11 @@ struct RelayDetailView: View {
|
|||||||
.navigationBarBackButtonHidden(true)
|
.navigationBarBackButtonHidden(true)
|
||||||
.navigationBarItems(leading: BackNav())
|
.navigationBarItems(leading: BackNav())
|
||||||
.ignoresSafeArea(.all)
|
.ignoresSafeArea(.all)
|
||||||
}
|
.toolbar {
|
||||||
|
if let relay_connection {
|
||||||
private func nipsList(nips: [Int]) -> AttributedString {
|
RelayStatusView(connection: relay_connection)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var relay_object: Relay? {
|
private var relay_object: Relay? {
|
||||||
@ -199,7 +214,11 @@ struct RelayDetailView: View {
|
|||||||
|
|
||||||
struct RelayDetailView_Previews: PreviewProvider {
|
struct RelayDetailView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
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)
|
RelayDetailView(state: test_damus_state, relay: RelayURL("wss://relay.damus.io")!, nip11: metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user