commit 874d15df45e0fd88e772187ea1561e483d5c8d2d
parent 713effdc35e2707cc5e163753493593806d023fb
Author: William Casarin <jb55@jb55.com>
Date: Mon, 16 May 2022 16:23:34 -0700
following view
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
8 files changed, 168 insertions(+), 37 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -32,6 +32,8 @@
4C363AA428296DEE006E126D /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA328296DEE006E126D /* SearchModel.swift */; };
4C363AA828297703006E126D /* InsertSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA728297703006E126D /* InsertSort.swift */; };
4C3AC79B28306D7B00E1F516 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79A28306D7B00E1F516 /* Contacts.swift */; };
+ 4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79C2833036D00E1F516 /* FollowingView.swift */; };
+ 4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3AC79E2833115300E1F516 /* FollowButtonView.swift */; };
4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */; };
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD32819DE8F00B3DE84 /* NostrKind.swift */; };
4C3BEFD6281D995700B3DE84 /* ActionBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD5281D995700B3DE84 /* ActionBarModel.swift */; };
@@ -117,6 +119,8 @@
4C363AA328296DEE006E126D /* SearchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchModel.swift; sourceTree = "<group>"; };
4C363AA728297703006E126D /* InsertSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertSort.swift; sourceTree = "<group>"; };
4C3AC79A28306D7B00E1F516 /* Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contacts.swift; sourceTree = "<group>"; };
+ 4C3AC79C2833036D00E1F516 /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = "<group>"; };
+ 4C3AC79E2833115300E1F516 /* FollowButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowButtonView.swift; sourceTree = "<group>"; };
4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileModel.swift; sourceTree = "<group>"; };
4C3BEFD32819DE8F00B3DE84 /* NostrKind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrKind.swift; sourceTree = "<group>"; };
4C3BEFD5281D995700B3DE84 /* ActionBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionBarModel.swift; sourceTree = "<group>"; };
@@ -234,6 +238,8 @@
4C363A8B28236B92006E126D /* PubkeyView.swift */,
4C363A8D28236FE4006E126D /* NoteContentView.swift */,
4C363AA128296A7E006E126D /* SearchView.swift */,
+ 4C3AC79C2833036D00E1F516 /* FollowingView.swift */,
+ 4C3AC79E2833115300E1F516 /* FollowButtonView.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -481,6 +487,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */,
4C363A8A28236B57006E126D /* MentionView.swift in Sources */,
4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */,
4C363AA828297703006E126D /* InsertSort.swift in Sources */,
@@ -509,6 +516,7 @@
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */,
4C3BEFE0281DE1ED00B3DE84 /* DamusState.swift in Sources */,
4C0A3F8F280F640A000448DE /* ThreadModel.swift in Sources */,
+ 4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */,
4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */,
4C0A3F93280F66F5000448DE /* ReplyMap.swift in Sources */,
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
diff --git a/damus/ContentView.swift b/damus/ContentView.swift
@@ -208,8 +208,7 @@ struct ContentView: View {
Group {
if let pk = self.active_profile {
let profile_model = ProfileModel(pubkey: pk, damus: damus_state!)
- let fs = damus_state!.contacts.follow_state(pk)
- ProfileView(damus: damus_state!, follow_state: fs, profile: profile_model)
+ ProfileView(damus_state: damus_state!, profile: profile_model)
} else {
EmptyView()
}
diff --git a/damus/Models/ProfileModel.swift b/damus/Models/ProfileModel.swift
@@ -9,17 +9,18 @@ import Foundation
class ProfileModel: ObservableObject {
@Published var events: [NostrEvent] = []
+ @Published var contacts: NostrEvent? = nil
+ @Published var following: Int = 0
+
let pubkey: String
let damus: DamusState
- @Published var following: Bool
var seen_event: Set<String> = Set()
var sub_id = UUID().description
init(pubkey: String, damus: DamusState) {
self.pubkey = pubkey
self.damus = damus
- self.following = damus.contacts.is_friend(pubkey)
}
func unsubscribe() {
@@ -44,13 +45,19 @@ class ProfileModel: ObservableObject {
damus.pool.subscribe(sub_id: sub_id, filters: [filter], handler: handle_event)
}
+ func handle_profile_contact_event(_ ev: NostrEvent) {
+ self.contacts = ev
+ self.following = count_pubkeys(ev.tags)
+ }
+
func add_event(_ ev: NostrEvent) {
if seen_event.contains(ev.id) {
return
}
- if ev.kind == 1 {
- self.events.append(ev)
- self.events = self.events.sorted { $0.created_at > $1.created_at }
+ if ev.known_kind == .text {
+ let _ = insert_uniq_sorted_event(events: &self.events, new_ev: ev, cmp: { $0.created_at > $1.created_at})
+ } else if ev.known_kind == .contacts {
+ handle_profile_contact_event(ev)
}
seen_event.insert(ev.id)
}
@@ -72,3 +79,15 @@ class ProfileModel: ObservableObject {
}
}
}
+
+
+func count_pubkeys(_ tags: [[String]]) -> Int {
+ var c: Int = 0
+ for tag in tags {
+ if tag.count >= 2 && tag[0] == "p" {
+ c += 1
+ }
+ }
+
+ return c
+}
diff --git a/damus/Nostr/NostrEvent.swift b/damus/Nostr/NostrEvent.swift
@@ -19,10 +19,14 @@ struct KeyEvent {
let relay_url: String
}
-struct ReferencedId {
+struct ReferencedId: Identifiable {
let ref_id: String
let relay_id: String?
let key: String
+
+ var id: String {
+ return ref_id
+ }
}
struct EventId: Identifiable, CustomStringConvertible {
diff --git a/damus/Views/EventView.swift b/damus/Views/EventView.swift
@@ -69,8 +69,7 @@ struct EventView: View {
let profile = damus.profiles.lookup(id: event.pubkey)
VStack {
let pmodel = ProfileModel(pubkey: event.pubkey, damus: damus)
- let fs = damus.contacts.follow_state(event.pubkey)
- let pv = ProfileView(damus: damus, follow_state: fs, profile: pmodel)
+ let pv = ProfileView(damus_state: damus, profile: pmodel)
NavigationLink(destination: pv) {
ProfilePicView(pubkey: event.pubkey, size: PFP_SIZE!, highlight: highlight, image_cache: damus.image_cache, profiles: damus.profiles)
@@ -122,9 +121,15 @@ struct EventView: View {
}
Button {
+ UIPasteboard.general.string = "@" + event.pubkey
+ } label: {
+ Label("Copy User ID", systemImage: "tag")
+ }
+
+ Button {
UIPasteboard.general.string = "&" + event.id
} label: {
- Label("Copy ID", systemImage: "tag")
+ Label("Copy Note ID", systemImage: "tag")
}
Button {
diff --git a/damus/Views/FollowButtonView.swift b/damus/Views/FollowButtonView.swift
@@ -0,0 +1,44 @@
+//
+// FollowButtonView.swift
+// damus
+//
+// Created by William Casarin on 2022-05-16.
+//
+
+import SwiftUI
+
+struct FollowButtonView: View {
+ let pubkey: String
+ @State var follow_state: FollowState
+
+ var body: some View {
+ Button("\(follow_btn_txt(follow_state))") {
+ follow_state = perform_follow_btn_action(follow_state, target: pubkey)
+ }
+ .buttonStyle(.bordered)
+ .onReceive(handle_notify(.followed)) { notif in
+ let pk = notif.object as! String
+ if pk != pubkey {
+ return
+ }
+
+ self.follow_state = .follows
+ }
+ .onReceive(handle_notify(.unfollowed)) { notif in
+ let pk = notif.object as! String
+ if pk != pubkey {
+ return
+ }
+
+ self.follow_state = .unfollows
+ }
+ }
+}
+
+ /*
+struct FollowButtonView_Previews: PreviewProvider {
+ static var previews: some View {
+ FollowButtonView()
+ }
+}
+ */
diff --git a/damus/Views/FollowingView.swift b/damus/Views/FollowingView.swift
@@ -0,0 +1,59 @@
+//
+// FollowingView.swift
+// damus
+//
+// Created by William Casarin on 2022-05-16.
+//
+
+import SwiftUI
+
+struct FollowUserView: View {
+ let pubkey: String
+ let damus_state: DamusState
+
+ var body: some View {
+ HStack(alignment: .top) {
+ let pmodel = ProfileModel(pubkey: pubkey, damus: damus_state)
+ let pv = ProfileView(damus_state: damus_state, profile: pmodel)
+
+ NavigationLink(destination: pv) {
+ ProfilePicView(pubkey: pubkey, size: PFP_SIZE!, highlight: .none, image_cache: damus_state.image_cache, profiles: damus_state.profiles)
+ }
+
+ VStack(alignment: .leading) {
+ let profile = damus_state.profiles.lookup(id: pubkey)
+ ProfileName(pubkey: pubkey, profile: profile)
+ if let about = profile.flatMap { $0.about } {
+ Text(about)
+ }
+ }
+
+ Spacer()
+
+ FollowButtonView(pubkey: pubkey, follow_state: damus_state.contacts.follow_state(pubkey))
+ }
+ }
+}
+
+struct FollowingView: View {
+ let contact: NostrEvent
+ let damus_state: DamusState
+
+ var body: some View {
+ ScrollView {
+ LazyVStack(alignment: .leading) {
+ ForEach(contact.referenced_pubkeys) { pk in
+ FollowUserView(pubkey: pk.ref_id, damus_state: damus_state)
+ }
+ }
+ }
+ }
+}
+
+/*
+struct FollowingView_Previews: PreviewProvider {
+ static var previews: some View {
+ FollowingView(contact: <#NostrEvent#>, damus_state: <#DamusState#>)
+ }
+}
+ */
diff --git a/damus/Views/ProfileView.swift b/damus/Views/ProfileView.swift
@@ -61,9 +61,8 @@ func perform_follow_btn_action(_ fs: FollowState, target: String) -> FollowState
}
struct ProfileView: View {
- let damus: DamusState
+ let damus_state: DamusState
- @State var follow_state: FollowState = .follows
@State private var selected_tab: ProfileTab = .posts
@StateObject var profile: ProfileModel
@@ -71,32 +70,13 @@ struct ProfileView: View {
var TopSection: some View {
VStack(alignment: .leading) {
- let data = damus.profiles.lookup(id: profile.pubkey)
+ let data = damus_state.profiles.lookup(id: profile.pubkey)
HStack(alignment: .top) {
- ProfilePicView(pubkey: profile.pubkey, size: PFP_SIZE!, highlight: .custom(Color.black, 2), image_cache: damus.image_cache, profiles: damus.profiles)
+ ProfilePicView(pubkey: profile.pubkey, size: PFP_SIZE!, highlight: .custom(Color.black, 2), image_cache: damus_state.image_cache, profiles: damus_state.profiles)
Spacer()
- Button("\(follow_btn_txt(follow_state))") {
- follow_state = perform_follow_btn_action(follow_state, target: profile.pubkey)
- }
- .buttonStyle(.bordered)
- .onReceive(handle_notify(.followed)) { notif in
- let pk = notif.object as! String
- if pk != profile.pubkey {
- return
- }
-
- self.follow_state = .follows
- }
- .onReceive(handle_notify(.unfollowed)) { notif in
- let pk = notif.object as! String
- if pk != profile.pubkey {
- return
- }
-
- self.follow_state = .unfollows
- }
+ FollowButtonView(pubkey: profile.pubkey, follow_state: damus_state.contacts.follow_state(profile.pubkey))
}
if let pubkey = profile.pubkey {
@@ -108,7 +88,21 @@ struct ProfileView: View {
.font(.footnote)
.foregroundColor(id_to_color(pubkey))
}
+
Text(data?.about ?? "")
+
+ if let contact = profile.contacts {
+ Divider()
+
+ NavigationLink(destination: FollowingView(contact: contact, damus_state: damus_state)) {
+ HStack {
+ Text("\(profile.following)")
+ Text("Following")
+ .foregroundColor(.gray)
+ }
+ }
+ .buttonStyle(PlainButtonStyle())
+ }
}
}
@@ -119,7 +113,7 @@ struct ProfileView: View {
Divider()
- InnerTimelineView(events: $profile.events, damus: damus)
+ InnerTimelineView(events: $profile.events, damus: damus_state)
}
.frame(maxHeight: .infinity, alignment: .topLeading)
}
@@ -128,7 +122,6 @@ struct ProfileView: View {
.navigationBarTitle("Profile")
.onAppear() {
- follow_state = damus.contacts.follow_state(profile.pubkey)
profile.subscribe()
}
.onDisappear {