commit 14a3a352d6e31d6b0143efd3032391fc9c0e44d4
parent 3824e95f296719fd8cf8a266f89e163cfce15cc4
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 29 Dec 2022 16:08:00 -0800
Recommended relay view
Changelog-Changed: Show recommended relays in config. Currently just a fixed set.
Diffstat:
7 files changed, 101 insertions(+), 46 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -109,6 +109,7 @@
 		4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */; };
 		4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */; };
 		4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9DB280C38C000D9BBE8 /* Profiles.swift */; };
+		4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */; };
 		4CD7641B28A1641400B6928F /* EndBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD7641A28A1641400B6928F /* EndBlock.swift */; };
 		4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F8CC281352B30009DFBB /* Notifications.swift */; };
 		4CE4F9DE2852768D00C00DD9 /* ConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F9DD2852768D00C00DD9 /* ConfigView.swift */; };
@@ -288,6 +289,7 @@
 		4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineView.swift; sourceTree = "<group>"; };
 		4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyView.swift; sourceTree = "<group>"; };
 		4CACA9DB280C38C000D9BBE8 /* Profiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Profiles.swift; sourceTree = "<group>"; };
+		4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendedRelayView.swift; sourceTree = "<group>"; };
 		4CD7641A28A1641400B6928F /* EndBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndBlock.swift; sourceTree = "<group>"; };
 		4CE4F8CC281352B30009DFBB /* Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
 		4CE4F9DD2852768D00C00DD9 /* ConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigView.swift; sourceTree = "<group>"; };
@@ -486,6 +488,7 @@
 				E990020E2955F837003BBC5A /* EditMetadataView.swift */,
 				BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */,
 				E9E4ED0A295867B900DD7078 /* ThreadV2View.swift */,
+				4CB55EF2295E5D59007FD187 /* RecommendedRelayView.swift */,
 			);
 			path = Views;
 			sourceTree = "<group>";
@@ -860,6 +863,7 @@
 				4C3BEFDA281DCA1400B3DE84 /* LikeCounter.swift in Sources */,
 				4C3AC79B28306D7B00E1F516 /* Contacts.swift in Sources */,
 				4C3EA63D28FF52D600C48A62 /* bolt11.c in Sources */,
+				4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */,
 				4C5F9118283D88E40052CD1C /* FollowingModel.swift in Sources */,
 				4C3EA67D28FFBBA300C48A62 /* InvoicesView.swift in Sources */,
 				4C363A8E28236FE4006E126D /* NoteContentView.swift in Sources */,
diff --git a/damus/ContentView.swift b/damus/ContentView.swift
@@ -16,6 +16,7 @@ var BOOTSTRAP_RELAYS = [
     "wss://relay.nostr.bg",
     "wss://nostr.oxtr.dev",
     "wss://nostr.v0l.io",
+    "wss://nostr-2.zebedee.cloud",
 ]
 
 struct TimestampedProfile {
diff --git a/damus/Models/Contacts.swift b/damus/Models/Contacts.swift
@@ -144,6 +144,7 @@ func remove_relay(ev: NostrEvent, current_relays: [RelayDescriptor], privkey: St
     
     relays.removeValue(forKey: relay)
     
+    print("remove_relay \(relays)")
     guard let content = encode_json(relays) else {
         return nil
     }
@@ -154,10 +155,9 @@ func remove_relay(ev: NostrEvent, current_relays: [RelayDescriptor], privkey: St
     return new_ev
 }
 
-func add_relay(ev: NostrEvent, privkey: String, relay: String, info: RelayInfo) -> NostrEvent? {
-    let damus_relay = RelayDescriptor(url: URL(string: "wss://relay.damus.io")!, info: .rw)
+func add_relay(ev: NostrEvent, privkey: String, current_relays: [RelayDescriptor], relay: String, info: RelayInfo) -> NostrEvent? {
+    var relays = ensure_relay_info(relays: current_relays, content: ev.content)
     
-    var relays = ensure_relay_info(relays: [damus_relay], content: ev.content)
     guard relays.index(forKey: relay) == nil else {
         return nil
     }
diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift
@@ -623,26 +623,3 @@ func load_our_relays(contacts: Contacts, our_pubkey: String, pool: RelayPool, m_
 }
 
 
-func remove_bootstrap_nodes(_ damus_state: DamusState) {
-    guard let contacts = damus_state.contacts.event else {
-        return
-    }
-
-    guard let relays = decode_json_relays(contacts.content) else {
-        return
-    }
-
-    let descriptors = relays.reduce(into: []) { arr, kv in
-        guard let url = URL(string: kv.key) else {
-            return
-        }
-        arr.append(RelayDescriptor(url: url, info: kv.value))
-    }
-
-    for relay in BOOTSTRAP_RELAYS {
-        if !(descriptors.contains { ($0 as! RelayDescriptor).url.absoluteString == relay }) {
-            damus_state.pool.remove_relay(relay)
-        }
-    }
-}
-
diff --git a/damus/Views/ConfigView.swift b/damus/Views/ConfigView.swift
@@ -18,11 +18,14 @@ struct ConfigView: View {
     @State var privkey_copied: Bool = false
     @State var pubkey_copied: Bool = false
     
+    @State var relays: [RelayDescriptor]
+    
     let generator = UIImpactFeedbackGenerator(style: .light)
     
     init(state: DamusState) {
         self.state = state
         _privkey = State(initialValue: self.state.keypair.privkey_bech32 ?? "")
+        _relays = State(initialValue: state.pool.descriptors)
     }
     
     // TODO: (jb55) could be more general but not gonna worry about it atm
@@ -38,12 +41,28 @@ struct ConfigView: View {
         }
     }
     
+    var recommended: [RelayDescriptor] {
+        let rs: [RelayDescriptor] = []
+        return BOOTSTRAP_RELAYS.reduce(into: rs) { (xs, x) in
+            if let _ = state.pool.get_relay(x) {
+            } else {
+                xs.append(RelayDescriptor(url: URL(string: x)!, info: .rw))
+            }
+        }
+    }
+    
     var body: some View {
         ZStack(alignment: .leading) {
             Form {
                 Section("Relays") {
-                    List(Array(state.pool.relays), id: \.descriptor.url) { relay in
-                        RelayView(state: state, relay: relay.descriptor.url.absoluteString)
+                    List(Array(relays), id: \.url) { relay in
+                        RelayView(state: state, relay: relay.url.absoluteString)
+                    }
+                }
+                
+                Section("Recommended Relays") {
+                    List(recommended, id: \.url) { r in
+                        RecommendedRelayView(damus: state, relay: r.url.absoluteString)
                     }
                 }
                 
@@ -133,17 +152,21 @@ struct ConfigView: View {
                 
                 state.pool.connect(to: [new_relay])
                 
-                guard let new_ev = add_relay(ev: ev, privkey: privkey, relay: new_relay, info: info) else {
+                guard let new_ev = add_relay(ev: ev, privkey: privkey, current_relays: state.pool.descriptors, relay: new_relay, info: info) else {
                     return
                 }
                 
-                state.contacts.event = new_ev
+                process_contact_event(pool: state.pool, contacts: state.contacts, pubkey: state.pubkey, ev: ev)
+                
                 state.pool.send(.event(new_ev))
             }
         }
         .onReceive(handle_notify(.switched_timeline)) { _ in
             dismiss()
         }
+        .onReceive(handle_notify(.relays_changed)) { _ in
+            self.relays = state.pool.descriptors
+        }
     }
 }
 
diff --git a/damus/Views/RecommendedRelayView.swift b/damus/Views/RecommendedRelayView.swift
@@ -0,0 +1,37 @@
+//
+//  RecommendedRelayView.swift
+//  damus
+//
+//  Created by William Casarin on 2022-12-29.
+//
+
+import SwiftUI
+
+struct RecommendedRelayView: View {
+    let damus: DamusState
+    let relay: String
+    
+    var body: some View {
+        HStack {
+            Text(relay)
+            Spacer()
+            if let ev = damus.contacts.event {
+                if let privkey = damus.keypair.privkey {
+                    Button("Add") {
+                        guard let ev = add_relay(ev: ev, privkey: privkey, current_relays: damus.pool.descriptors, relay: relay, info: .rw) else {
+                            return
+                        }
+                        process_contact_event(pool: damus.pool, contacts: damus.contacts, pubkey: damus.pubkey, ev: ev)
+                        damus.pool.send(.event(ev))
+                    }
+                }
+            }
+        }
+    }
+}
+
+struct RecommendedRelayView_Previews: PreviewProvider {
+    static var previews: some View {
+        RecommendedRelayView(damus: test_damus_state(), relay: "wss://relay.damus.io")
+    }
+}
diff --git a/damus/Views/RelayView.swift b/damus/Views/RelayView.swift
@@ -44,28 +44,41 @@ struct RelayView: View {
         }
         .swipeActions {
             if let privkey = state.keypair.privkey {
-                Button {
-                    guard let ev = state.contacts.event else {
-                        return
-                    }
-                    
-                    let descriptors = state.pool.descriptors
-                    guard let new_ev = remove_relay( ev: ev, current_relays: descriptors, privkey: privkey, relay: relay) else {
-                        return
-                    }
-                    
-                    state.contacts.event = new_ev
-                    state.pool.send(.event(new_ev))
-                } label: {
-                    Label("Delete", systemImage: "trash")
-                }
-                .tint(.red)
+                RemoveAction(privkey: privkey)
+            }
+        }
+        .contextMenu {
+            if let privkey = state.keypair.privkey {
+                RemoveAction(privkey: privkey)
+            }
+        }
+    }
+    
+    func RemoveAction(privkey: String) -> some View {
+        Button {
+            guard let ev = state.contacts.event else {
+                return
+            }
+            
+            let descriptors = state.pool.descriptors
+            guard let new_ev = remove_relay( ev: ev, current_relays: descriptors, privkey: privkey, relay: relay) else {
+                return
             }
+            
+            process_contact_event(pool: state.pool, contacts: state.contacts, pubkey: state.pubkey, ev: new_ev)
+            state.pool.send(.event(new_ev))
+        } label: {
+            Label("Delete", systemImage: "trash")
         }
+        .tint(.red)
     }
     
 }
 
+fileprivate func remove_action() {
+    
+}
+
 struct RelayView_Previews: PreviewProvider {
     static var previews: some View {
         RelayView(state: test_damus_state(), relay: "wss://relay.damus.io", conn_color: .red)