@@ -71,6 +71,7 @@
|
|||||||
4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD17283A9EE5008EE7EF /* LoginView.swift */; };
|
4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD17283A9EE5008EE7EF /* LoginView.swift */; };
|
||||||
4C90BD1A283AA67F008EE7EF /* Bech32.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD19283AA67F008EE7EF /* Bech32.swift */; };
|
4C90BD1A283AA67F008EE7EF /* Bech32.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD19283AA67F008EE7EF /* Bech32.swift */; };
|
||||||
4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */; };
|
4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */; };
|
||||||
|
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C987B56283FD07F0042CE38 /* FollowersModel.swift */; };
|
||||||
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */; };
|
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */; };
|
||||||
4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */; };
|
4CACA9D5280C31E100D9BBE8 /* ReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */; };
|
||||||
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9DB280C38C000D9BBE8 /* Profiles.swift */; };
|
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACA9DB280C38C000D9BBE8 /* Profiles.swift */; };
|
||||||
@@ -177,6 +178,7 @@
|
|||||||
4C90BD17283A9EE5008EE7EF /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
4C90BD17283A9EE5008EE7EF /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
||||||
4C90BD19283AA67F008EE7EF /* Bech32.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32.swift; sourceTree = "<group>"; };
|
4C90BD19283AA67F008EE7EF /* Bech32.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32.swift; sourceTree = "<group>"; };
|
||||||
4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Tests.swift; sourceTree = "<group>"; };
|
4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Tests.swift; sourceTree = "<group>"; };
|
||||||
|
4C987B56283FD07F0042CE38 /* FollowersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersModel.swift; sourceTree = "<group>"; };
|
||||||
4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineView.swift; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
4CACA9DB280C38C000D9BBE8 /* Profiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Profiles.swift; sourceTree = "<group>"; };
|
||||||
@@ -253,6 +255,7 @@
|
|||||||
4C5F9113283D694D0052CD1C /* FollowTarget.swift */,
|
4C5F9113283D694D0052CD1C /* FollowTarget.swift */,
|
||||||
4C5F9115283D855D0052CD1C /* EventsModel.swift */,
|
4C5F9115283D855D0052CD1C /* EventsModel.swift */,
|
||||||
4C5F9117283D88E40052CD1C /* FollowingModel.swift */,
|
4C5F9117283D88E40052CD1C /* FollowingModel.swift */,
|
||||||
|
4C987B56283FD07F0042CE38 /* FollowersModel.swift */,
|
||||||
);
|
);
|
||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -558,6 +561,7 @@
|
|||||||
4C75EFB92804A2740006080F /* EventView.swift in Sources */,
|
4C75EFB92804A2740006080F /* EventView.swift in Sources */,
|
||||||
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
|
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
|
||||||
4C633350283D40E500B1C9C3 /* HomeModel.swift in Sources */,
|
4C633350283D40E500B1C9C3 /* HomeModel.swift in Sources */,
|
||||||
|
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */,
|
||||||
4C363A9828283441006E126D /* TestingPrivate.swift in Sources */,
|
4C363A9828283441006E126D /* TestingPrivate.swift in Sources */,
|
||||||
4C363A9028247A1D006E126D /* NostrLink.swift in Sources */,
|
4C363A9028247A1D006E126D /* NostrLink.swift in Sources */,
|
||||||
4C0A3F8C280F5FCA000448DE /* ChatroomView.swift in Sources */,
|
4C0A3F8C280F5FCA000448DE /* ChatroomView.swift in Sources */,
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ struct ContentView: View {
|
|||||||
Group {
|
Group {
|
||||||
if let pk = self.active_profile {
|
if let pk = self.active_profile {
|
||||||
let profile_model = ProfileModel(pubkey: pk, damus: damus_state!)
|
let profile_model = ProfileModel(pubkey: pk, damus: damus_state!)
|
||||||
ProfileView(damus_state: damus_state!, profile: profile_model)
|
let followers = FollowersModel(damus_state: damus_state!, target: pk)
|
||||||
|
ProfileView(damus_state: damus_state!, profile: profile_model, followers: followers)
|
||||||
} else {
|
} else {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
@@ -355,13 +356,11 @@ struct ContentView: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
struct ContentView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ContentView()
|
ContentView(keypair: Keypair(pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681", privkey: nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
func get_since_time(last_event: NostrEvent?) -> Int64? {
|
func get_since_time(last_event: NostrEvent?) -> Int64? {
|
||||||
@@ -372,26 +371,6 @@ func get_since_time(last_event: NostrEvent?) -> Int64? {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func fetch_profiles(relay: URL, pubkeys: [String]) {
|
|
||||||
return NostrFilter(ids: nil, kinds: 3, event_ids: nil, pubkeys: pubkeys, since: nil, until: nil, authors: pubkeys)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func nostr_req(relays: [URL], filter: NostrFilter) {
|
|
||||||
if relays.count == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let conn = NostrConnection(url: relay) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func get_profiles()
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
func ws_nostr_event(relay: String, ev: WebSocketEvent) -> NostrEvent? {
|
func ws_nostr_event(relay: String, ev: WebSocketEvent) -> NostrEvent? {
|
||||||
switch ev {
|
switch ev {
|
||||||
case .binary(let dat):
|
case .binary(let dat):
|
||||||
|
|||||||
66
damus/Models/FollowersModel.swift
Normal file
66
damus/Models/FollowersModel.swift
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// FollowersModel.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2022-05-26.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class FollowersModel: ObservableObject {
|
||||||
|
let damus_state: DamusState
|
||||||
|
let target: String
|
||||||
|
var needs_sub: Bool = true
|
||||||
|
|
||||||
|
@Published var contacts: [String] = []
|
||||||
|
var has_contact: Set<String> = Set()
|
||||||
|
|
||||||
|
let sub_id: String = UUID().description
|
||||||
|
|
||||||
|
init(damus_state: DamusState, target: String) {
|
||||||
|
self.damus_state = damus_state
|
||||||
|
self.target = target
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_filter() -> NostrFilter {
|
||||||
|
var filter = NostrFilter.filter_contacts
|
||||||
|
filter.pubkeys = [target]
|
||||||
|
return filter
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribe() {
|
||||||
|
let filter = get_filter()
|
||||||
|
let filters = [filter]
|
||||||
|
print_filters(relay_id: "following", filters: [filters])
|
||||||
|
self.damus_state.pool.subscribe(sub_id: sub_id, filters: filters, handler: handle_event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsubscribe() {
|
||||||
|
self.damus_state.pool.unsubscribe(sub_id: sub_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_contact_event(_ ev: NostrEvent) {
|
||||||
|
if has_contact.contains(ev.pubkey) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
process_contact_event(contacts: damus_state.contacts, pubkey: damus_state.pubkey, ev: ev)
|
||||||
|
contacts.append(ev.pubkey)
|
||||||
|
has_contact.insert(ev.pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_event(relay_id: String, ev: NostrConnectionEvent) {
|
||||||
|
switch ev {
|
||||||
|
case .ws_event:
|
||||||
|
break
|
||||||
|
case .nostr_event(let nev):
|
||||||
|
switch nev {
|
||||||
|
case .event(_, let ev):
|
||||||
|
if ev.kind == 3 {
|
||||||
|
handle_contact_event(ev)
|
||||||
|
}
|
||||||
|
case .notice(let msg):
|
||||||
|
print("followingmodel notice: \(msg)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class FollowingModel: ObservableObject {
|
class FollowingModel {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
var needs_sub: Bool = true
|
var needs_sub: Bool = true
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ struct EventView: View {
|
|||||||
let profile = damus.profiles.lookup(id: event.pubkey)
|
let profile = damus.profiles.lookup(id: event.pubkey)
|
||||||
VStack {
|
VStack {
|
||||||
let pmodel = ProfileModel(pubkey: event.pubkey, damus: damus)
|
let pmodel = ProfileModel(pubkey: event.pubkey, damus: damus)
|
||||||
let pv = ProfileView(damus_state: damus, profile: pmodel)
|
let pv = ProfileView(damus_state: damus, profile: pmodel, followers: FollowersModel(damus_state: damus, target: event.pubkey))
|
||||||
|
|
||||||
NavigationLink(destination: pv) {
|
NavigationLink(destination: pv) {
|
||||||
ProfilePicView(pubkey: event.pubkey, size: PFP_SIZE, highlight: highlight, image_cache: damus.image_cache, profiles: damus.profiles)
|
ProfilePicView(pubkey: event.pubkey, size: PFP_SIZE, highlight: highlight, image_cache: damus.image_cache, profiles: damus.profiles)
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ struct FollowUserView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
let pmodel = ProfileModel(pubkey: target.pubkey, damus: damus_state)
|
let pmodel = ProfileModel(pubkey: target.pubkey, damus: damus_state)
|
||||||
let pv = ProfileView(damus_state: damus_state, profile: pmodel)
|
let followers = FollowersModel(damus_state: damus_state, target: target.pubkey)
|
||||||
|
let pv = ProfileView(damus_state: damus_state, profile: pmodel, followers: followers)
|
||||||
|
|
||||||
NavigationLink(destination: pv) {
|
NavigationLink(destination: pv) {
|
||||||
ProfilePicView(pubkey: target.pubkey, size: PFP_SIZE, highlight: .none, image_cache: damus_state.image_cache, profiles: damus_state.profiles)
|
ProfilePicView(pubkey: target.pubkey, size: PFP_SIZE, highlight: .none, image_cache: damus_state.image_cache, profiles: damus_state.profiles)
|
||||||
@@ -35,11 +36,27 @@ struct FollowUserView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FollowersView: View {
|
||||||
|
let damus_state: DamusState
|
||||||
|
|
||||||
|
@EnvironmentObject var followers: FollowersModel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollView {
|
||||||
|
LazyVStack(alignment: .leading) {
|
||||||
|
ForEach(followers.contacts, id: \.self) { pk in
|
||||||
|
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
struct FollowingView: View {
|
struct FollowingView: View {
|
||||||
let damus_state: DamusState
|
let damus_state: DamusState
|
||||||
|
|
||||||
@StateObject var following: FollowingModel
|
let following: FollowingModel
|
||||||
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ struct ProfileView: View {
|
|||||||
|
|
||||||
@State private var selected_tab: ProfileTab = .posts
|
@State private var selected_tab: ProfileTab = .posts
|
||||||
@StateObject var profile: ProfileModel
|
@StateObject var profile: ProfileModel
|
||||||
|
@StateObject var followers: FollowersModel
|
||||||
|
|
||||||
//@EnvironmentObject var profile: ProfileModel
|
//@EnvironmentObject var profile: ProfileModel
|
||||||
|
|
||||||
@@ -88,14 +89,27 @@ struct ProfileView: View {
|
|||||||
|
|
||||||
let contacts = contact.referenced_pubkeys.map { $0.ref_id }
|
let contacts = contact.referenced_pubkeys.map { $0.ref_id }
|
||||||
let following_model = FollowingModel(damus_state: damus_state, contacts: contacts)
|
let following_model = FollowingModel(damus_state: damus_state, contacts: contacts)
|
||||||
NavigationLink(destination: FollowingView(damus_state: damus_state, following: following_model)) {
|
HStack {
|
||||||
HStack {
|
NavigationLink(destination: FollowingView(damus_state: damus_state, following: following_model)) {
|
||||||
Text("\(profile.following)")
|
HStack {
|
||||||
Text("Following")
|
Text("\(profile.following)")
|
||||||
.foregroundColor(.gray)
|
Text("Following")
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
|
||||||
|
let fview = FollowersView(damus_state: damus_state)
|
||||||
|
.environmentObject(followers)
|
||||||
|
NavigationLink(destination: fview) {
|
||||||
|
HStack {
|
||||||
|
Text("\(followers.contacts.count)")
|
||||||
|
Text("Followers")
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,9 +131,11 @@ struct ProfileView: View {
|
|||||||
.navigationBarTitle("Profile")
|
.navigationBarTitle("Profile")
|
||||||
.onAppear() {
|
.onAppear() {
|
||||||
profile.subscribe()
|
profile.subscribe()
|
||||||
|
followers.subscribe()
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
profile.unsubscribe()
|
profile.unsubscribe()
|
||||||
|
followers.unsubscribe()
|
||||||
// our profilemodel needs a bit more help
|
// our profilemodel needs a bit more help
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,8 +144,9 @@ struct ProfileView: View {
|
|||||||
struct ProfileView_Previews: PreviewProvider {
|
struct ProfileView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let ds = test_damus_state()
|
let ds = test_damus_state()
|
||||||
|
let followers = FollowersModel(damus_state: ds, target: ds.pubkey)
|
||||||
let profile_model = ProfileModel(pubkey: ds.pubkey, damus: ds)
|
let profile_model = ProfileModel(pubkey: ds.pubkey, damus: ds)
|
||||||
ProfileView(damus_state: ds, profile: profile_model)
|
ProfileView(damus_state: ds, profile: profile_model, followers: followers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user