damus

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

commit 97fbee85c061b410b7d0d6ad58a53aa6dae53d97
parent 967c4639763473240c59d520b04286ab5f981d3a
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 13 Apr 2022 12:18:01 -0700

posting, global timeline

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Mdamus/ContentView.swift | 81++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mdamus/Nostr/NostrEvent.swift | 5++++-
Mdamus/Nostr/NostrFilter.swift | 12++++++++++--
Adamus/Nostr/NostrTimeline.swift | 8++++++++
Mdamus/Nostr/RelayConnection.swift | 4+++-
6 files changed, 91 insertions(+), 23 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */; }; 4CEE2AEB2805AEA300AB5EEF /* secp256k1 in Frameworks */ = {isa = PBXBuildFile; productRef = 4CEE2AEA2805AEA300AB5EEF /* secp256k1 */; }; 4CEE2AED2805B22500AB5EEF /* NostrRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AEC2805B22500AB5EEF /* NostrRequest.swift */; }; + 4CEE2AEF2805BE2500AB5EEF /* NostrTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AEE2805BE2500AB5EEF /* NostrTimeline.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -73,6 +74,7 @@ 4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConnection.swift; sourceTree = "<group>"; }; 4CEE2AE72804F57C00AB5EEF /* libsecp256k1.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libsecp256k1.a; sourceTree = "<group>"; }; 4CEE2AEC2805B22500AB5EEF /* NostrRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrRequest.swift; sourceTree = "<group>"; }; + 4CEE2AEE2805BE2500AB5EEF /* NostrTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrTimeline.swift; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -125,6 +127,7 @@ 4C75EFB628049D990006080F /* RelayPool.swift */, 4C75EFBA2804A34C0006080F /* ProofOfWork.swift */, 4CEE2AEC2805B22500AB5EEF /* NostrRequest.swift */, + 4CEE2AEE2805BE2500AB5EEF /* NostrTimeline.swift */, ); path = Nostr; sourceTree = "<group>"; @@ -344,6 +347,7 @@ 4C75EFA627FF87A20006080F /* Nostr.swift in Sources */, 4C75EFB328049D640006080F /* NostrEvent.swift in Sources */, 4C75EFB128049D510006080F /* NostrResponse.swift in Sources */, + 4CEE2AEF2805BE2500AB5EEF /* NostrTimeline.swift in Sources */, 4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */, 4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */, 4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */, diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -27,37 +27,66 @@ enum Sheets: Identifiable { } } +enum Timeline { + case friends + case global +} + struct ContentView: View { @State var status: String = "Not connected" - @State var sub_id: String? = nil @State var active_sheet: Sheets? = nil @State var events: [NostrEvent] = [] @State var profiles: [String: TimestampedProfile] = [:] + @State var friends: [String: ()] = [:] @State var has_events: [String: ()] = [:] @State var profile_count: Int = 0 @State var last_event_of_kind: [Int: NostrEvent] = [:] @State var loading: Bool = true + @State var timeline: Timeline = .friends @State var pool: RelayPool? = nil + let pubkey = "fd3fdb0d0d8d6f9a7667b53211de8ae3c5246b79bdaf64ebac849d5148b5615f" + var MainContent: some View { ScrollView { ForEach(events, id: \.id) { - EventView(event: $0, profile: profiles[$0.pubkey]?.profile) + if timeline == .global || (timeline == .friends && is_friend($0.pubkey)) { + EventView(event: $0, profile: profiles[$0.pubkey]?.profile) + } } } } - var body: some View { - ZStack { - MainContent - .padding() - VStack { - Spacer() + var TopBar: some View { + HStack { + Button(action: {switch_timeline(.friends)}) { + Label("", systemImage: "person.2") + } + .padding([.trailing], 50.0) + .foregroundColor(self.timeline == .global ? .gray : .primary) - HStack { + Button(action: {switch_timeline(.global)}) { + Label("", systemImage: "globe.americas") + } + .padding([.leading], 50.0) + .foregroundColor(self.timeline == .friends ? .gray : .primary) + } + } + + var body: some View { + VStack { + TopBar + ZStack { + MainContent + .padding() + VStack { Spacer() - PostButton() { - self.active_sheet = .post + + HStack { + Spacer() + PostButton() { + self.active_sheet = .post + } } } } @@ -74,7 +103,6 @@ struct ContentView: View { .onReceive(NotificationCenter.default.publisher(for: .post)) { obj in let post = obj.object as! NostrPost print("post \(post.content)") - let pubkey = "" let privkey = "" let new_ev = NostrEvent(content: post.content, pubkey: pubkey) new_ev.sign(privkey: privkey) @@ -82,6 +110,14 @@ struct ContentView: View { } } + func is_friend(_ pubkey: String) -> Bool { + return pubkey == self.pubkey || self.friends[pubkey] != nil + } + + func switch_timeline(_ timeline: Timeline) { + self.timeline = timeline + } + func connect() { let pool = RelayPool(handle_event: handle_event) @@ -94,6 +130,14 @@ struct ContentView: View { } func handle_contact_event(_ ev: NostrEvent) { + if ev.pubkey == self.pubkey { + // our contacts + for tag in ev.tags { + if tag.count > 1 && tag[0] == "p" { + self.friends[tag[1]] = () + } + } + } } func handle_metadata_event(_ ev: NostrEvent) { @@ -127,12 +171,12 @@ struct ContentView: View { profile_filter.since = prof_since } - let filters = [since_filter, profile_filter] + var contacts_filter = NostrFilter.filter_contacts + contacts_filter.authors = [self.pubkey] + + let filters = [since_filter, profile_filter, contacts_filter] print("connected to \(relay_id), refreshing from \(since)") - let sub_id = self.sub_id ?? UUID().description - if self.sub_id != sub_id { - self.sub_id = sub_id - } + let sub_id = UUID().description print("subscribing to \(sub_id)") self.pool?.send(.subscribe(.init(filters: filters, sub_id: sub_id))) } @@ -161,7 +205,6 @@ struct ContentView: View { if self.loading { self.loading = false } - self.sub_id = sub_id if has_events[ev.id] == nil { has_events[ev.id] = () @@ -213,7 +256,7 @@ func get_metadata_since_time(_ metadata_event: NostrEvent?) -> Int64? { func get_since_time(last_event: NostrEvent?) -> Int64 { if last_event == nil { - return Int64(Date().timeIntervalSince1970) - (24 * 60 * 60 * 3) + return Int64(Date().timeIntervalSince1970) - (24 * 60 * 60 * 4) } return last_event!.created_at - 60 * 10 diff --git a/damus/Nostr/NostrEvent.swift b/damus/Nostr/NostrEvent.swift @@ -115,7 +115,10 @@ func decode_data<T: Decodable>(_ data: Data) -> T? { } func event_commitment(ev: NostrEvent, tags: String) -> String { - return "[0,\"\(ev.pubkey)\",\(ev.created_at),\(ev.kind),\(tags),\"\(ev.content)\"]" + let encoder = JSONEncoder() + let str_data = try! encoder.encode(ev.content) + let content = String(decoding: str_data, as: UTF8.self) + return "[0,\"\(ev.pubkey)\",\(ev.created_at),\(ev.kind),\(tags),\(content)]" } func calculate_event_id(ev: NostrEvent) -> String { diff --git a/damus/Nostr/NostrFilter.swift b/damus/Nostr/NostrFilter.swift @@ -27,11 +27,19 @@ struct NostrFilter: Codable { } public static var filter_text: NostrFilter { - NostrFilter(ids: nil, kinds: [1], referenced_ids: nil, pubkeys: nil, since: nil, until: nil, authors: nil) + return filter_kinds([1]) } public static var filter_profiles: NostrFilter { - return NostrFilter(ids: nil, kinds: [0], referenced_ids: nil, pubkeys: nil, since: nil, until: nil, authors: nil) + return filter_kinds([0]) + } + + public static var filter_contacts: NostrFilter { + return filter_kinds([3]) + } + + public static func filter_kinds(_ kinds: [Int]) -> NostrFilter { + return NostrFilter(ids: nil, kinds: kinds, referenced_ids: nil, pubkeys: nil, since: nil, until: nil, authors: nil) } public static func filter_since(_ val: Int64) -> NostrFilter { diff --git a/damus/Nostr/NostrTimeline.swift b/damus/Nostr/NostrTimeline.swift @@ -0,0 +1,8 @@ +// +// NostrTimeline.swift +// damus +// +// Created by William Casarin on 2022-04-12. +// + +import Foundation diff --git a/damus/Nostr/RelayConnection.swift b/damus/Nostr/RelayConnection.swift @@ -84,7 +84,9 @@ func make_nostr_push_event(ev: NostrEvent) -> String? { let encoder = JSONEncoder() let event_data = try! encoder.encode(ev) let event = String(decoding: event_data, as: UTF8.self) - return "[\"EVENT\",\(event)]" + let encoded = "[\"EVENT\",\(event)]" + print(encoded) + return encoded } func make_nostr_subscription_req(_ filters: [NostrFilter], sub_id: String) -> String? {