insert sort, profile updates revamp
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -28,6 +28,9 @@
|
|||||||
4C363A9C282838B9006E126D /* EventRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A9B282838B9006E126D /* EventRef.swift */; };
|
4C363A9C282838B9006E126D /* EventRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A9B282838B9006E126D /* EventRef.swift */; };
|
||||||
4C363A9E2828A822006E126D /* ReplyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A9D2828A822006E126D /* ReplyTests.swift */; };
|
4C363A9E2828A822006E126D /* ReplyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A9D2828A822006E126D /* ReplyTests.swift */; };
|
||||||
4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A9F2828A8DD006E126D /* LikeTests.swift */; };
|
4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A9F2828A8DD006E126D /* LikeTests.swift */; };
|
||||||
|
4C363AA228296A7E006E126D /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA128296A7E006E126D /* SearchView.swift */; };
|
||||||
|
4C363AA428296DEE006E126D /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA328296DEE006E126D /* SearchModel.swift */; };
|
||||||
|
4C363AA828297703006E126D /* InsertSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363AA728297703006E126D /* InsertSort.swift */; };
|
||||||
4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */; };
|
4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */; };
|
||||||
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD32819DE8F00B3DE84 /* NostrKind.swift */; };
|
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD32819DE8F00B3DE84 /* NostrKind.swift */; };
|
||||||
4C3BEFD6281D995700B3DE84 /* ActionBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD5281D995700B3DE84 /* ActionBarModel.swift */; };
|
4C3BEFD6281D995700B3DE84 /* ActionBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD5281D995700B3DE84 /* ActionBarModel.swift */; };
|
||||||
@@ -108,6 +111,9 @@
|
|||||||
4C363A9B282838B9006E126D /* EventRef.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventRef.swift; sourceTree = "<group>"; };
|
4C363A9B282838B9006E126D /* EventRef.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventRef.swift; sourceTree = "<group>"; };
|
||||||
4C363A9D2828A822006E126D /* ReplyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyTests.swift; sourceTree = "<group>"; };
|
4C363A9D2828A822006E126D /* ReplyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyTests.swift; sourceTree = "<group>"; };
|
||||||
4C363A9F2828A8DD006E126D /* LikeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeTests.swift; sourceTree = "<group>"; };
|
4C363A9F2828A8DD006E126D /* LikeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeTests.swift; sourceTree = "<group>"; };
|
||||||
|
4C363AA128296A7E006E126D /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = "<group>"; };
|
||||||
|
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>"; };
|
||||||
4C3BEFD12819DB9B00B3DE84 /* ProfileModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileModel.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>"; };
|
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>"; };
|
4C3BEFD5281D995700B3DE84 /* ActionBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionBarModel.swift; sourceTree = "<group>"; };
|
||||||
@@ -195,6 +201,7 @@
|
|||||||
4C363A952827096D006E126D /* PostBlock.swift */,
|
4C363A952827096D006E126D /* PostBlock.swift */,
|
||||||
4C363A9928283854006E126D /* Reply.swift */,
|
4C363A9928283854006E126D /* Reply.swift */,
|
||||||
4C363A9B282838B9006E126D /* EventRef.swift */,
|
4C363A9B282838B9006E126D /* EventRef.swift */,
|
||||||
|
4C363AA328296DEE006E126D /* SearchModel.swift */,
|
||||||
);
|
);
|
||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -221,6 +228,7 @@
|
|||||||
4C363A8928236B57006E126D /* MentionView.swift */,
|
4C363A8928236B57006E126D /* MentionView.swift */,
|
||||||
4C363A8B28236B92006E126D /* PubkeyView.swift */,
|
4C363A8B28236B92006E126D /* PubkeyView.swift */,
|
||||||
4C363A8D28236FE4006E126D /* NoteContentView.swift */,
|
4C363A8D28236FE4006E126D /* NoteContentView.swift */,
|
||||||
|
4C363AA128296A7E006E126D /* SearchView.swift */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -249,6 +257,7 @@
|
|||||||
children = (
|
children = (
|
||||||
4C363A8328233689006E126D /* Parser.swift */,
|
4C363A8328233689006E126D /* Parser.swift */,
|
||||||
4C363A8528234FDE006E126D /* ImageCache.swift */,
|
4C363A8528234FDE006E126D /* ImageCache.swift */,
|
||||||
|
4C363AA728297703006E126D /* InsertSort.swift */,
|
||||||
);
|
);
|
||||||
path = Util;
|
path = Util;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -468,12 +477,14 @@
|
|||||||
files = (
|
files = (
|
||||||
4C363A8A28236B57006E126D /* MentionView.swift in Sources */,
|
4C363A8A28236B57006E126D /* MentionView.swift in Sources */,
|
||||||
4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */,
|
4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */,
|
||||||
|
4C363AA828297703006E126D /* InsertSort.swift in Sources */,
|
||||||
4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */,
|
4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */,
|
||||||
4C363A8628234FDE006E126D /* ImageCache.swift in Sources */,
|
4C363A8628234FDE006E126D /* ImageCache.swift in Sources */,
|
||||||
4C75EFB728049D990006080F /* RelayPool.swift in Sources */,
|
4C75EFB728049D990006080F /* RelayPool.swift in Sources */,
|
||||||
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */,
|
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */,
|
||||||
4CEE2AF5280B29E600AB5EEF /* TimeAgo.swift in Sources */,
|
4CEE2AF5280B29E600AB5EEF /* TimeAgo.swift in Sources */,
|
||||||
4C75EFAD28049CFB0006080F /* PostButton.swift in Sources */,
|
4C75EFAD28049CFB0006080F /* PostButton.swift in Sources */,
|
||||||
|
4C363AA228296A7E006E126D /* SearchView.swift in Sources */,
|
||||||
4C75EFB92804A2740006080F /* EventView.swift in Sources */,
|
4C75EFB92804A2740006080F /* EventView.swift in Sources */,
|
||||||
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
|
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
|
||||||
4C363A9828283441006E126D /* TestingPrivate.swift in Sources */,
|
4C363A9828283441006E126D /* TestingPrivate.swift in Sources */,
|
||||||
@@ -501,6 +512,7 @@
|
|||||||
4C8682872814DE470026224F /* ProfileView.swift in Sources */,
|
4C8682872814DE470026224F /* ProfileView.swift in Sources */,
|
||||||
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
|
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
|
||||||
4C3BEFD6281D995700B3DE84 /* ActionBarModel.swift in Sources */,
|
4C3BEFD6281D995700B3DE84 /* ActionBarModel.swift in Sources */,
|
||||||
|
4C363AA428296DEE006E126D /* SearchModel.swift in Sources */,
|
||||||
4CEE2AF3280B25C500AB5EEF /* ProfilePicView.swift in Sources */,
|
4CEE2AF3280B25C500AB5EEF /* ProfilePicView.swift in Sources */,
|
||||||
4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */,
|
4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */,
|
||||||
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */,
|
4C3BEFD42819DE8F00B3DE84 /* NostrKind.swift in Sources */,
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ enum Timeline: String, CustomStringConvertible {
|
|||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
@State var status: String = "Not connected"
|
@State var status: String = "Not connected"
|
||||||
@State var active_sheet: Sheets? = nil
|
@State var active_sheet: Sheets? = nil
|
||||||
@State var profiles: Profiles = Profiles()
|
|
||||||
@State var friends: [String: ()] = [:]
|
@State var friends: [String: ()] = [:]
|
||||||
@State var loading: Bool = true
|
@State var loading: Bool = true
|
||||||
@State var damus: DamusState? = nil
|
@State var damus: DamusState? = nil
|
||||||
@@ -59,9 +58,11 @@ struct ContentView: View {
|
|||||||
@State var friend_events: [NostrEvent] = []
|
@State var friend_events: [NostrEvent] = []
|
||||||
@State var notifications: [NostrEvent] = []
|
@State var notifications: [NostrEvent] = []
|
||||||
@State var active_profile: String? = nil
|
@State var active_profile: String? = nil
|
||||||
|
@State var active_search: NostrFilter? = nil
|
||||||
@State var active_event_id: String? = nil
|
@State var active_event_id: String? = nil
|
||||||
@State var profile_open: Bool = false
|
@State var profile_open: Bool = false
|
||||||
@State var thread_open: Bool = false
|
@State var thread_open: Bool = false
|
||||||
|
@State var search_open: Bool = false
|
||||||
|
|
||||||
// connect retry timer
|
// connect retry timer
|
||||||
let timer = Timer.publish(every: 60, on: .main, in: .common).autoconnect()
|
let timer = Timer.publish(every: 60, on: .main, in: .common).autoconnect()
|
||||||
@@ -142,7 +143,6 @@ struct ContentView: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
if let damus = self.damus {
|
if let damus = self.damus {
|
||||||
TimelineView(events: $friend_events, damus: damus)
|
TimelineView(events: $friend_events, damus: damus)
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
PostButtonContainer
|
PostButtonContainer
|
||||||
}
|
}
|
||||||
@@ -157,6 +157,9 @@ struct ContentView: View {
|
|||||||
NavigationLink(destination: MaybeThreadView, isActive: $thread_open) {
|
NavigationLink(destination: MaybeThreadView, isActive: $thread_open) {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
|
NavigationLink(destination: MaybeSearchView, isActive: $search_open) {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
switch selected_timeline {
|
switch selected_timeline {
|
||||||
case .home:
|
case .home:
|
||||||
PostingTimelineView
|
PostingTimelineView
|
||||||
@@ -166,13 +169,11 @@ struct ContentView: View {
|
|||||||
|
|
||||||
case .notifications:
|
case .notifications:
|
||||||
TimelineView(events: $notifications, damus: damus)
|
TimelineView(events: $notifications, damus: damus)
|
||||||
.environmentObject(profiles)
|
|
||||||
.navigationTitle("Notifications")
|
.navigationTitle("Notifications")
|
||||||
|
|
||||||
case .global:
|
case .global:
|
||||||
|
|
||||||
TimelineView(events: $events, damus: damus)
|
TimelineView(events: $events, damus: damus)
|
||||||
.environmentObject(profiles)
|
|
||||||
.navigationTitle("Global")
|
.navigationTitle("Global")
|
||||||
case .none:
|
case .none:
|
||||||
EmptyView()
|
EmptyView()
|
||||||
@@ -184,12 +185,21 @@ struct ContentView: View {
|
|||||||
.navigationViewStyle(.stack)
|
.navigationViewStyle(.stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var MaybeSearchView: some View {
|
||||||
|
Group {
|
||||||
|
if let search = self.active_search {
|
||||||
|
SearchView(appstate: damus!, search: SearchModel(pool: damus!.pool, search: search))
|
||||||
|
} else {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var MaybeThreadView: some View {
|
var MaybeThreadView: some View {
|
||||||
Group {
|
Group {
|
||||||
if let evid = self.active_event_id {
|
if let evid = self.active_event_id {
|
||||||
let thread_model = ThreadModel(evid: evid, pool: damus!.pool)
|
let thread_model = ThreadModel(evid: evid, pool: damus!.pool)
|
||||||
ThreadView(thread: thread_model, damus: damus!)
|
ThreadView(thread: thread_model, damus: damus!)
|
||||||
.environmentObject(profiles)
|
|
||||||
} else {
|
} else {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
@@ -201,7 +211,6 @@ struct ContentView: View {
|
|||||||
if let pk = self.active_profile {
|
if let pk = self.active_profile {
|
||||||
let profile_model = ProfileModel(pubkey: pk, damus: damus!)
|
let profile_model = ProfileModel(pubkey: pk, damus: damus!)
|
||||||
ProfileView(damus: damus!, profile: profile_model)
|
ProfileView(damus: damus!, profile: profile_model)
|
||||||
.environmentObject(profiles)
|
|
||||||
} else {
|
} else {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
@@ -230,7 +239,6 @@ struct ContentView: View {
|
|||||||
PostView(references: [])
|
PostView(references: [])
|
||||||
case .reply(let event):
|
case .reply(let event):
|
||||||
ReplyView(replying_to: event, damus: damus!)
|
ReplyView(replying_to: event, damus: damus!)
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onOpenURL { url in
|
.onOpenURL { url in
|
||||||
@@ -247,8 +255,9 @@ struct ContentView: View {
|
|||||||
active_event_id = ref.ref_id
|
active_event_id = ref.ref_id
|
||||||
thread_open = true
|
thread_open = true
|
||||||
}
|
}
|
||||||
case .filter:
|
case .filter(let filt):
|
||||||
|
active_search = filt
|
||||||
|
search_open = true
|
||||||
break
|
break
|
||||||
// TODO: handle filter searches?
|
// TODO: handle filter searches?
|
||||||
}
|
}
|
||||||
@@ -340,10 +349,12 @@ struct ContentView: View {
|
|||||||
func add_relay(_ pool: RelayPool, _ relay: String) {
|
func add_relay(_ pool: RelayPool, _ relay: String) {
|
||||||
//add_rw_relay(pool, "wss://nostr-pub.wellorder.net")
|
//add_rw_relay(pool, "wss://nostr-pub.wellorder.net")
|
||||||
add_rw_relay(pool, relay)
|
add_rw_relay(pool, relay)
|
||||||
|
/*
|
||||||
let profile = Profile(name: relay, about: nil, picture: nil)
|
let profile = Profile(name: relay, about: nil, picture: nil)
|
||||||
let ts = Int64(Date().timeIntervalSince1970)
|
let ts = Int64(Date().timeIntervalSince1970)
|
||||||
let tsprofile = TimestampedProfile(profile: profile, timestamp: ts)
|
let tsprofile = TimestampedProfile(profile: profile, timestamp: ts)
|
||||||
self.profiles.add(id: relay, profile: tsprofile)
|
damus!.profiles.add(id: relay, profile: tsprofile)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect() {
|
func connect() {
|
||||||
@@ -361,7 +372,8 @@ struct ContentView: View {
|
|||||||
self.damus = DamusState(pool: pool, pubkey: pubkey,
|
self.damus = DamusState(pool: pool, pubkey: pubkey,
|
||||||
likes: EventCounter(our_pubkey: pubkey),
|
likes: EventCounter(our_pubkey: pubkey),
|
||||||
boosts: EventCounter(our_pubkey: pubkey),
|
boosts: EventCounter(our_pubkey: pubkey),
|
||||||
image_cache: ImageCache()
|
image_cache: ImageCache(),
|
||||||
|
profiles: Profiles()
|
||||||
)
|
)
|
||||||
pool.connect()
|
pool.connect()
|
||||||
}
|
}
|
||||||
@@ -404,7 +416,7 @@ struct ContentView: View {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if let mprof = self.profiles.lookup_with_timestamp(id: ev.pubkey) {
|
if let mprof = damus!.profiles.lookup_with_timestamp(id: ev.pubkey) {
|
||||||
if mprof.timestamp > ev.created_at {
|
if mprof.timestamp > ev.created_at {
|
||||||
// skip if we already have an newer profile
|
// skip if we already have an newer profile
|
||||||
return
|
return
|
||||||
@@ -412,7 +424,9 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tprof = TimestampedProfile(profile: profile, timestamp: ev.created_at)
|
let tprof = TimestampedProfile(profile: profile, timestamp: ev.created_at)
|
||||||
self.profiles.add(id: ev.pubkey, profile: tprof)
|
damus!.profiles.add(id: ev.pubkey, profile: tprof)
|
||||||
|
|
||||||
|
notify(.profile_updated, ProfileUpdate(pubkey: ev.pubkey, profile: profile))
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_last_event_of_kind(relay_id: String, kind: Int) -> NostrEvent? {
|
func get_last_event_of_kind(relay_id: String, kind: Int) -> NostrEvent? {
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ struct DamusState {
|
|||||||
let likes: EventCounter
|
let likes: EventCounter
|
||||||
let boosts: EventCounter
|
let boosts: EventCounter
|
||||||
let image_cache: ImageCache
|
let image_cache: ImageCache
|
||||||
|
let profiles: Profiles
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ enum EventRef {
|
|||||||
|
|
||||||
var is_thread_id: ReferencedId? {
|
var is_thread_id: ReferencedId? {
|
||||||
switch self {
|
switch self {
|
||||||
case .mention(let mention):
|
case .mention:
|
||||||
return nil
|
return nil
|
||||||
case .thread_id(let referencedId):
|
case .thread_id(let referencedId):
|
||||||
return referencedId
|
return referencedId
|
||||||
case .reply(let referencedId):
|
case .reply:
|
||||||
return nil
|
return nil
|
||||||
case .reply_to_root(let referencedId):
|
case .reply_to_root(let referencedId):
|
||||||
return referencedId
|
return referencedId
|
||||||
|
|||||||
74
damus/Models/SearchModel.swift
Normal file
74
damus/Models/SearchModel.swift
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// Timeline.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2022-05-09.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
class SearchModel: ObservableObject {
|
||||||
|
@Published var events: [NostrEvent] = []
|
||||||
|
let pool: RelayPool
|
||||||
|
let search: NostrFilter
|
||||||
|
let sub_id = UUID().description
|
||||||
|
|
||||||
|
init(pool: RelayPool, search: NostrFilter) {
|
||||||
|
self.pool = pool
|
||||||
|
self.search = search
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribe() {
|
||||||
|
// since 2 month
|
||||||
|
var filter = NostrFilter.copy(from: search)
|
||||||
|
filter.since = Int64(Date.now.timeIntervalSince1970) - 2629800 * 2
|
||||||
|
|
||||||
|
//likes_filter.ids = ref_events.referenced_ids!
|
||||||
|
|
||||||
|
print("subscribing to search '\(filter)' with sub_id \(sub_id)")
|
||||||
|
pool.register_handler(sub_id: sub_id, handler: handle_event)
|
||||||
|
pool.send(.subscribe(.init(filters: [filter], sub_id: sub_id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsubscribe() {
|
||||||
|
self.pool.unsubscribe(sub_id: sub_id)
|
||||||
|
print("unsubscribing from search '\(search)' with sub_id \(sub_id)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func add_event(_ ev: NostrEvent) {
|
||||||
|
if insert_uniq_sorted_event(events: &self.events, new_ev: ev) {
|
||||||
|
objectWillChange.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_event(relay_id: String, ev: NostrConnectionEvent) {
|
||||||
|
handle_subid_event(pool: pool, sub_id: sub_id, relay_id: relay_id, ev: ev) { ev in
|
||||||
|
if ev.known_kind == .text {
|
||||||
|
self.add_event(ev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func handle_subid_event(pool: RelayPool, sub_id: String, relay_id: String, ev: NostrConnectionEvent, handle: (NostrEvent) -> ()) {
|
||||||
|
switch ev {
|
||||||
|
case .ws_event:
|
||||||
|
break
|
||||||
|
case .nostr_event(let res):
|
||||||
|
switch res {
|
||||||
|
case .event(let ev_subid, let ev):
|
||||||
|
if ev_subid == sub_id {
|
||||||
|
handle(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
case .notice(let note):
|
||||||
|
if note.contains("Too many subscription filters") {
|
||||||
|
// TODO: resend filters?
|
||||||
|
pool.reconnect(to: [relay_id])
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -140,9 +140,11 @@ class ThreadModel: ObservableObject {
|
|||||||
self.replies.add(id: ev.id, reply_id: reply.ref_id)
|
self.replies.add(id: ev.id, reply_id: reply.ref_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.events.append(ev)
|
if insert_uniq_sorted_event(events: &self.events, new_ev: ev) {
|
||||||
self.events = self.events.sorted { $0.created_at < $1.created_at }
|
objectWillChange.send()
|
||||||
//objectWillChange.send()
|
}
|
||||||
|
//self.events.append(ev)
|
||||||
|
//self.events = self.events.sorted { $0.created_at < $1.created_at }
|
||||||
|
|
||||||
var i: Int = 0
|
var i: Int = 0
|
||||||
for ev in events {
|
for ev in events {
|
||||||
@@ -160,24 +162,9 @@ class ThreadModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handle_event(relay_id: String, ev: NostrConnectionEvent) {
|
func handle_event(relay_id: String, ev: NostrConnectionEvent) {
|
||||||
switch ev {
|
handle_subid_event(pool: pool, sub_id: sub_id, relay_id: relay_id, ev: ev) { ev in
|
||||||
case .ws_event:
|
if ev.known_kind == .text {
|
||||||
break
|
self.add_event(ev)
|
||||||
case .nostr_event(let res):
|
|
||||||
switch res {
|
|
||||||
case .event(let sub_id, let ev):
|
|
||||||
if sub_id == self.sub_id {
|
|
||||||
if ev.known_kind == .text {
|
|
||||||
add_event(ev)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case .notice(let note):
|
|
||||||
if note.contains("Too many subscription filters") {
|
|
||||||
// TODO: resend filters?
|
|
||||||
pool.reconnect(to: [relay_id])
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ struct NostrFilter: Codable {
|
|||||||
case authors
|
case authors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func copy(from: NostrFilter) -> NostrFilter {
|
||||||
|
return NostrFilter(ids: from.ids, kinds: from.kinds, referenced_ids: from.referenced_ids, pubkeys: from.pubkeys, since: from.since, until: from.until, authors: from.authors, hashtag: from.hashtag)
|
||||||
|
}
|
||||||
|
|
||||||
public static func filter_hashtag(_ htags: [String]) -> NostrFilter {
|
public static func filter_hashtag(_ htags: [String]) -> NostrFilter {
|
||||||
return NostrFilter(ids: nil, kinds: nil, referenced_ids: nil, pubkeys: nil, since: nil, until: nil, authors: nil, hashtag: htags)
|
return NostrFilter(ids: nil, kinds: nil, referenced_ids: nil, pubkeys: nil, since: nil, until: nil, authors: nil, hashtag: htags)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ func decode_nostr_uri(_ s: String) -> NostrLink? {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if parts.count >= 3 && parts[1] == "hashtag" {
|
if parts.count >= 2 && parts[0] == "hashtag" {
|
||||||
return .filter(NostrFilter.filter_hashtag([parts[2]]))
|
return .filter(NostrFilter.filter_hashtag([parts[1]]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return tag_to_refid(parts).map { .ref($0) }
|
return tag_to_refid(parts).map { .ref($0) }
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ import UIKit
|
|||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
|
|
||||||
class Profiles: ObservableObject {
|
class Profiles {
|
||||||
@Published var profiles: [String: TimestampedProfile] = [:]
|
var profiles: [String: TimestampedProfile] = [:]
|
||||||
|
|
||||||
func add(id: String, profile: TimestampedProfile) {
|
func add(id: String, profile: TimestampedProfile) {
|
||||||
profiles[id] = profile
|
profiles[id] = profile
|
||||||
objectWillChange.send()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookup(id: String) -> Profile? {
|
func lookup(id: String) -> Profile? {
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ extension Notification.Name {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension Notification.Name {
|
extension Notification.Name {
|
||||||
static var profile_update: Notification.Name {
|
static var profile_updated: Notification.Name {
|
||||||
return Notification.Name("profile_update")
|
return Notification.Name("profile_updated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
damus/Util/InsertSort.swift
Normal file
29
damus/Util/InsertSort.swift
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// InsertSort.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2022-05-09.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
func insert_uniq_sorted_event(events: inout [NostrEvent], new_ev: NostrEvent) -> Bool {
|
||||||
|
var i: Int = 0
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
// don't insert duplicate events
|
||||||
|
if new_ev.id == event.id {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_ev.created_at < event.created_at {
|
||||||
|
events.insert(new_ev, at: i)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
events.append(new_ev)
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -51,6 +51,10 @@ func parse_str(_ p: Parser, _ s: String) -> Bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parse_char(_ p: Parser, _ c: Character) -> Bool {
|
func parse_char(_ p: Parser, _ c: Character) -> Bool {
|
||||||
|
if p.pos >= p.str.count {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
let ind = p.str.index(p.str.startIndex, offsetBy: p.pos)
|
let ind = p.str.index(p.str.startIndex, offsetBy: p.pos)
|
||||||
|
|
||||||
if p.str[ind] == c {
|
if p.str[ind] == c {
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ struct ChatView: View {
|
|||||||
|
|
||||||
let damus: DamusState
|
let damus: DamusState
|
||||||
|
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
@EnvironmentObject var thread: ThreadModel
|
@EnvironmentObject var thread: ThreadModel
|
||||||
|
|
||||||
var just_started: Bool {
|
var just_started: Bool {
|
||||||
@@ -72,7 +71,7 @@ struct ChatView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ReplyDescription: some View {
|
var ReplyDescription: some View {
|
||||||
Text("\(reply_desc(profiles: profiles, event: event))")
|
Text("\(reply_desc(profiles: damus.profiles, event: event))")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
.frame(alignment: .leading)
|
.frame(alignment: .leading)
|
||||||
@@ -84,8 +83,7 @@ struct ChatView: View {
|
|||||||
HStack {
|
HStack {
|
||||||
VStack {
|
VStack {
|
||||||
if is_active || just_started {
|
if is_active || just_started {
|
||||||
ProfilePicView(pubkey: event.pubkey, size: 32, highlight: is_active ? .main : .none, image_cache: damus.image_cache)
|
ProfilePicView(pubkey: event.pubkey, size: 32, highlight: is_active ? .main : .none, image_cache: damus.image_cache, profiles: damus.profiles)
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -96,7 +94,7 @@ struct ChatView: View {
|
|||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
if just_started {
|
if just_started {
|
||||||
HStack {
|
HStack {
|
||||||
ProfileName(pubkey: event.pubkey, profile: profiles.lookup(id: event.pubkey))
|
ProfileName(pubkey: event.pubkey, profile: damus.profiles.lookup(id: event.pubkey))
|
||||||
.foregroundColor(colorScheme == .dark ? id_to_color(event.pubkey) : Color.black)
|
.foregroundColor(colorScheme == .dark ? id_to_color(event.pubkey) : Color.black)
|
||||||
//.shadow(color: Color.black, radius: 2)
|
//.shadow(color: Color.black, radius: 2)
|
||||||
Text("\(format_relative_time(event.created_at))")
|
Text("\(format_relative_time(event.created_at))")
|
||||||
@@ -106,21 +104,20 @@ struct ChatView: View {
|
|||||||
|
|
||||||
if let ref_id = thread.replies.lookup(event.id) {
|
if let ref_id = thread.replies.lookup(event.id) {
|
||||||
if !is_reply_to_prev() {
|
if !is_reply_to_prev() {
|
||||||
ReplyQuoteView(quoter: event, event_id: ref_id, image_cache: damus.image_cache)
|
ReplyQuoteView(quoter: event, event_id: ref_id, image_cache: damus.image_cache, profiles: damus.profiles)
|
||||||
.environmentObject(thread)
|
.environmentObject(thread)
|
||||||
.environmentObject(profiles)
|
|
||||||
ReplyDescription
|
ReplyDescription
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteContentView(event: event, profiles: profiles, content: event.content)
|
NoteContentView(event: event, profiles: damus.profiles, content: event.content)
|
||||||
|
|
||||||
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
if is_active || next_ev == nil || next_ev!.pubkey != event.pubkey {
|
||||||
EventActionBar(event: event,
|
EventActionBar(event: event,
|
||||||
our_pubkey: damus.pubkey,
|
our_pubkey: damus.pubkey,
|
||||||
|
profiles: damus.profiles,
|
||||||
bar: make_actionbar_model(ev: event, counter: damus.likes)
|
bar: make_actionbar_model(ev: event, counter: damus.likes)
|
||||||
)
|
)
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Spacer()
|
//Spacer()
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ struct EventActionBar: View {
|
|||||||
let event: NostrEvent
|
let event: NostrEvent
|
||||||
let our_pubkey: String
|
let our_pubkey: String
|
||||||
@State var sheet: ActionBarSheet? = nil
|
@State var sheet: ActionBarSheet? = nil
|
||||||
@EnvironmentObject var profiles: Profiles
|
let profiles: Profiles
|
||||||
@StateObject var bar: ActionBarModel
|
@StateObject var bar: ActionBarModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ struct EventDetailView: View {
|
|||||||
|
|
||||||
@StateObject var thread: ThreadModel
|
@StateObject var thread: ThreadModel
|
||||||
@State var collapsed: Bool = true
|
@State var collapsed: Bool = true
|
||||||
|
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
|
|
||||||
func toggle_collapse_thread(scroller: ScrollViewProxy, id mid: String?, animate: Bool = true, anchor: UnitPoint = .center) {
|
func toggle_collapse_thread(scroller: ScrollViewProxy, id mid: String?, animate: Bool = true, anchor: UnitPoint = .center) {
|
||||||
self.collapsed = !self.collapsed
|
self.collapsed = !self.collapsed
|
||||||
|
|||||||
@@ -42,19 +42,16 @@ struct EventView: View {
|
|||||||
let has_action_bar: Bool
|
let has_action_bar: Bool
|
||||||
let damus: DamusState
|
let damus: DamusState
|
||||||
|
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
@EnvironmentObject var action_bar: ActionBarModel
|
@EnvironmentObject var action_bar: ActionBarModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let profile = profiles.lookup(id: event.pubkey)
|
let profile = damus.profiles.lookup(id: event.pubkey)
|
||||||
HStack {
|
HStack {
|
||||||
VStack {
|
VStack {
|
||||||
let pv = ProfileView(damus: damus, profile: ProfileModel(pubkey: event.pubkey, damus: damus))
|
let pv = ProfileView(damus: damus, profile: ProfileModel(pubkey: event.pubkey, damus: damus))
|
||||||
.environmentObject(profiles)
|
|
||||||
|
|
||||||
NavigationLink(destination: pv) {
|
NavigationLink(destination: pv) {
|
||||||
ProfilePicView(pubkey: event.pubkey, size: PFP_SIZE!, highlight: highlight, image_cache: damus.image_cache)
|
ProfilePicView(pubkey: event.pubkey, size: PFP_SIZE!, highlight: highlight, image_cache: damus.image_cache, profiles: damus.profiles)
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -69,21 +66,20 @@ struct EventView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if event.is_reply {
|
if event.is_reply {
|
||||||
Text("\(reply_desc(profiles: profiles, event: event))")
|
Text("\(reply_desc(profiles: damus.profiles, event: event))")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteContentView(event: event, profiles: profiles, content: event.content)
|
NoteContentView(event: event, profiles: damus.profiles, content: event.content)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.textSelection(.enabled)
|
.textSelection(.enabled)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if has_action_bar {
|
if has_action_bar {
|
||||||
EventActionBar(event: event, our_pubkey: damus.pubkey, bar: make_actionbar_model(ev: event, counter: damus.likes))
|
EventActionBar(event: event, our_pubkey: damus.pubkey, profiles: damus.profiles, bar: make_actionbar_model(ev: event, counter: damus.likes))
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|||||||
@@ -9,14 +9,12 @@ import SwiftUI
|
|||||||
|
|
||||||
struct MentionView: View {
|
struct MentionView: View {
|
||||||
let mention: Mention
|
let mention: Mention
|
||||||
|
let profiles: Profiles
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
switch mention.type {
|
switch mention.type {
|
||||||
case .pubkey:
|
case .pubkey:
|
||||||
PubkeyView(pubkey: mention.ref.ref_id, relay: mention.ref.relay_id)
|
PubkeyView(pubkey: mention.ref.ref_id, relay: mention.ref.relay_id)
|
||||||
.environmentObject(profiles)
|
|
||||||
case .event:
|
case .event:
|
||||||
Text("< e >")
|
Text("< e >")
|
||||||
//EventBlockView(pubkey: mention.ref.ref_id, relay: mention.ref.relay_id)
|
//EventBlockView(pubkey: mention.ref.ref_id, relay: mention.ref.relay_id)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ struct NoteContentView: View {
|
|||||||
.onAppear() {
|
.onAppear() {
|
||||||
self.content = render_note_content(ev: event, profiles: profiles)
|
self.content = render_note_content(ev: event, profiles: profiles)
|
||||||
}
|
}
|
||||||
.onReceive(handle_notify(.profile_update)) { notif in
|
.onReceive(handle_notify(.profile_updated)) { notif in
|
||||||
let profile = notif.object as! ProfileUpdate
|
let profile = notif.object as! ProfileUpdate
|
||||||
for block in event.blocks {
|
for block in event.blocks {
|
||||||
switch block {
|
switch block {
|
||||||
|
|||||||
@@ -7,9 +7,24 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
func ProfileName(pubkey: String, profile: Profile?) -> some View {
|
struct ProfileName: View {
|
||||||
Text(String(Profile.displayName(profile: profile, pubkey: pubkey)))
|
let pubkey: String
|
||||||
//.foregroundColor(hex_to_rgb(pubkey))
|
let profile: Profile?
|
||||||
.bold()
|
|
||||||
|
@State var display_name: String?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Text(String(display_name ?? Profile.displayName(profile: profile, pubkey: pubkey)))
|
||||||
|
//.foregroundColor(hex_to_rgb(pubkey))
|
||||||
|
.bold()
|
||||||
|
.onReceive(handle_notify(.profile_updated)) { notif in
|
||||||
|
let update = notif.object as! ProfileUpdate
|
||||||
|
if update.pubkey != pubkey {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
display_name = Profile.displayName(profile: update.profile, pubkey: pubkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ struct ProfilePicView: View {
|
|||||||
let size: CGFloat
|
let size: CGFloat
|
||||||
let highlight: Highlight
|
let highlight: Highlight
|
||||||
let image_cache: ImageCache
|
let image_cache: ImageCache
|
||||||
|
let profiles: Profiles
|
||||||
|
|
||||||
|
@State var picture: String? = nil
|
||||||
@State var img: Image? = nil
|
@State var img: Image? = nil
|
||||||
|
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
|
|
||||||
var PlaceholderColor: Color {
|
var PlaceholderColor: Color {
|
||||||
return id_to_color(pubkey)
|
return id_to_color(pubkey)
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ struct ProfilePicView: View {
|
|||||||
|
|
||||||
var MainContent: some View {
|
var MainContent: some View {
|
||||||
Group {
|
Group {
|
||||||
let picture = profiles.lookup(id: pubkey)?.picture
|
let picture = picture ?? profiles.lookup(id: pubkey)?.picture
|
||||||
if let pic_url = picture.flatMap { URL(string: $0) } {
|
if let pic_url = picture.flatMap { URL(string: $0) } {
|
||||||
ProfilePic(pic_url)
|
ProfilePic(pic_url)
|
||||||
} else {
|
} else {
|
||||||
@@ -87,6 +87,16 @@ struct ProfilePicView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
MainContent
|
MainContent
|
||||||
|
.onReceive(handle_notify(.profile_updated)) { notif in
|
||||||
|
let updated = notif.object as! ProfileUpdate
|
||||||
|
if updated.pubkey != pubkey {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated.profile.picture != picture {
|
||||||
|
picture = updated.profile.picture
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ struct ProfileView: View {
|
|||||||
@StateObject var profile: ProfileModel
|
@StateObject var profile: ProfileModel
|
||||||
|
|
||||||
//@EnvironmentObject var profile: ProfileModel
|
//@EnvironmentObject var profile: ProfileModel
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
|
|
||||||
var TopSection: some View {
|
var TopSection: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
let data = profiles.lookup(id: profile.pubkey)
|
let data = damus.profiles.lookup(id: profile.pubkey)
|
||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
ProfilePicView(pubkey: profile.pubkey, size: PFP_SIZE!, highlight: .custom(Color.black, 2), image_cache: damus.image_cache)
|
ProfilePicView(pubkey: profile.pubkey, size: PFP_SIZE!, highlight: .custom(Color.black, 2), image_cache: damus.image_cache, profiles: damus.profiles)
|
||||||
.environmentObject(profiles)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
@@ -56,7 +54,6 @@ struct ProfileView: View {
|
|||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
InnerTimelineView(events: $profile.events, damus: damus)
|
InnerTimelineView(events: $profile.events, damus: damus)
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
.frame(maxHeight: .infinity, alignment: .topLeading)
|
.frame(maxHeight: .infinity, alignment: .topLeading)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ struct ReplyQuoteView: View {
|
|||||||
let quoter: NostrEvent
|
let quoter: NostrEvent
|
||||||
let event_id: String
|
let event_id: String
|
||||||
let image_cache: ImageCache
|
let image_cache: ImageCache
|
||||||
|
let profiles: Profiles
|
||||||
|
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
@EnvironmentObject var thread: ThreadModel
|
@EnvironmentObject var thread: ThreadModel
|
||||||
|
|
||||||
func MainContent(event: NostrEvent) -> some View {
|
func MainContent(event: NostrEvent) -> some View {
|
||||||
@@ -23,8 +23,7 @@ struct ReplyQuoteView: View {
|
|||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
ProfilePicView(pubkey: event.pubkey, size: 16, highlight: .reply, image_cache: image_cache)
|
ProfilePicView(pubkey: event.pubkey, size: 16, highlight: .reply, image_cache: image_cache, profiles: profiles)
|
||||||
.environmentObject(profiles)
|
|
||||||
Text(Profile.displayName(profile: profiles.lookup(id: event.pubkey), pubkey: event.pubkey))
|
Text(Profile.displayName(profile: profiles.lookup(id: event.pubkey), pubkey: event.pubkey))
|
||||||
.foregroundColor(.accentColor)
|
.foregroundColor(.accentColor)
|
||||||
Text("\(format_relative_time(event.created_at))")
|
Text("\(format_relative_time(event.created_at))")
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ struct ReplyView: View {
|
|||||||
let replying_to: NostrEvent
|
let replying_to: NostrEvent
|
||||||
let damus: DamusState
|
let damus: DamusState
|
||||||
|
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Text("Replying to:")
|
Text("Replying to:")
|
||||||
@@ -27,7 +25,7 @@ struct ReplyView: View {
|
|||||||
let names = all_referenced_pubkeys(replying_to)
|
let names = all_referenced_pubkeys(replying_to)
|
||||||
.map { pubkey in
|
.map { pubkey in
|
||||||
let pk = pubkey.ref_id
|
let pk = pubkey.ref_id
|
||||||
let prof = profiles.lookup(id: pk)
|
let prof = damus.profiles.lookup(id: pk)
|
||||||
return Profile.displayName(profile: prof, pubkey: pk)
|
return Profile.displayName(profile: prof, pubkey: pk)
|
||||||
}
|
}
|
||||||
.joined(separator: ", ")
|
.joined(separator: ", ")
|
||||||
|
|||||||
32
damus/Views/SearchView.swift
Normal file
32
damus/Views/SearchView.swift
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// SearchView.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2022-05-09.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SearchView: View {
|
||||||
|
let appstate: DamusState
|
||||||
|
@StateObject var search: SearchModel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
TimelineView(events: $search.events, damus: appstate)
|
||||||
|
.padding([.leading, .trailing], 6)
|
||||||
|
.onAppear() {
|
||||||
|
search.subscribe()
|
||||||
|
}
|
||||||
|
.onDisappear() {
|
||||||
|
search.unsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct SearchView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
SearchView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -13,7 +13,6 @@ struct ThreadView: View {
|
|||||||
@StateObject var thread: ThreadModel
|
@StateObject var thread: ThreadModel
|
||||||
let damus: DamusState
|
let damus: DamusState
|
||||||
|
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -21,12 +20,10 @@ struct ThreadView: View {
|
|||||||
if is_chatroom {
|
if is_chatroom {
|
||||||
ChatroomView(damus: damus)
|
ChatroomView(damus: damus)
|
||||||
.navigationBarTitle("Chat")
|
.navigationBarTitle("Chat")
|
||||||
.environmentObject(profiles)
|
|
||||||
.environmentObject(thread)
|
.environmentObject(thread)
|
||||||
} else {
|
} else {
|
||||||
EventDetailView(damus: damus, thread: thread)
|
EventDetailView(damus: damus, thread: thread)
|
||||||
.navigationBarTitle("Thread")
|
.navigationBarTitle("Thread")
|
||||||
.environmentObject(profiles)
|
|
||||||
.environmentObject(thread)
|
.environmentObject(thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,12 @@ enum TimelineAction {
|
|||||||
|
|
||||||
struct InnerTimelineView: View {
|
struct InnerTimelineView: View {
|
||||||
@Binding var events: [NostrEvent]
|
@Binding var events: [NostrEvent]
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
let damus: DamusState
|
let damus: DamusState
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
LazyVStack {
|
LazyVStack {
|
||||||
ForEach(events, id: \.id) { (ev: NostrEvent) in
|
ForEach(events, id: \.id) { (ev: NostrEvent) in
|
||||||
let tv = ThreadView(thread: ThreadModel(event: ev, pool: damus.pool), damus: damus)
|
let tv = ThreadView(thread: ThreadModel(event: ev, pool: damus.pool), damus: damus)
|
||||||
.environmentObject(profiles)
|
|
||||||
|
|
||||||
NavigationLink(destination: tv) {
|
NavigationLink(destination: tv) {
|
||||||
EventView(event: ev, highlight: .none, has_action_bar: true, damus: damus)
|
EventView(event: ev, highlight: .none, has_action_bar: true, damus: damus)
|
||||||
@@ -36,21 +34,17 @@ struct InnerTimelineView: View {
|
|||||||
struct TimelineView: View {
|
struct TimelineView: View {
|
||||||
@Binding var events: [NostrEvent]
|
@Binding var events: [NostrEvent]
|
||||||
|
|
||||||
@EnvironmentObject var profiles: Profiles
|
|
||||||
|
|
||||||
let damus: DamusState
|
let damus: DamusState
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
MainContent
|
MainContent
|
||||||
.padding([.leading, .trailing], 6)
|
.padding([.leading, .trailing], 6)
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var MainContent: some View {
|
var MainContent: some View {
|
||||||
ScrollViewReader { scroller in
|
ScrollViewReader { scroller in
|
||||||
ScrollView {
|
ScrollView {
|
||||||
InnerTimelineView(events: $events, damus: damus)
|
InnerTimelineView(events: $events, damus: damus)
|
||||||
.environmentObject(profiles)
|
|
||||||
}
|
}
|
||||||
.onReceive(NotificationCenter.default.publisher(for: .scroll_to_top)) { _ in
|
.onReceive(NotificationCenter.default.publisher(for: .scroll_to_top)) { _ in
|
||||||
guard let event = events.first else {
|
guard let event = events.first else {
|
||||||
|
|||||||
Reference in New Issue
Block a user