commit 6ce5484d74a340dde77a76e9db5f6694c66022bf
parent cca8738519702fc9eff32bf398e1dd935a619bc3
Author: William Casarin <jb55@jb55.com>
Date: Mon, 18 Apr 2022 10:31:54 -0700
calculate ancestor reply path
This works really well going back in time because no branching, assuming
the last referenced event id is the only note they are replying to...
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
3 files changed, 88 insertions(+), 22 deletions(-)
diff --git a/damus/Views/EventDetailView.swift b/damus/Views/EventDetailView.swift
@@ -10,7 +10,7 @@ import SwiftUI
enum CollapsedEvent: Identifiable {
case event(NostrEvent, Highlight)
case collapsed(Int, String)
-
+
var id: String {
switch self {
case .event(let ev, _):
@@ -29,9 +29,9 @@ struct EventDetailView: View {
@State var events: [NostrEvent] = []
@State var has_event: [String: ()] = [:]
@State var collapsed: Bool = true
-
+
@EnvironmentObject var profiles: Profiles
-
+
let pool: RelayPool
func unsubscribe_to_thread() {
@@ -54,7 +54,7 @@ struct EventDetailView: View {
pool.register_handler(sub_id: sub_id, handler: handle_event)
pool.send(.subscribe(.init(filters: [ref_events, events], sub_id: sub_id)))
}
-
+
func add_event(ev: NostrEvent) {
if sub_id != self.sub_id || self.has_event[ev.id] != nil {
return
@@ -72,7 +72,7 @@ struct EventDetailView: View {
if sub_id == self.sub_id {
add_event(ev: ev)
}
-
+
case .notice(let note):
if note.contains("Too many subscription filters") {
// TODO: resend filters?
@@ -82,14 +82,14 @@ struct EventDetailView: View {
}
}
}
-
+
func toggle_collapse_thread(scroller: ScrollViewProxy, id: String) {
self.collapsed = !self.collapsed
if !self.collapsed {
scroll_to_event(scroller: scroller, id: id, delay: 0.1)
}
}
-
+
func scroll_to_event(scroller: ScrollViewProxy, id: String, delay: Double) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
withAnimation {
@@ -97,7 +97,7 @@ struct EventDetailView: View {
}
}
}
-
+
func OurEventView(proxy: ScrollViewProxy, ev: NostrEvent, highlight: Highlight) -> some View {
Group {
if ev.id == event.id {
@@ -121,7 +121,7 @@ struct EventDetailView: View {
}
}
}
-
+
var body: some View {
ScrollViewReader { proxy in
ScrollView {
@@ -143,7 +143,7 @@ struct EventDetailView: View {
.onAppear() {
self.add_event(event)
subscribe_to_thread()
-
+
}
}
@@ -166,34 +166,100 @@ struct EventDetailView_Previews: PreviewProvider {
}
*/
+/// Find the entire reply path for the active event
+func make_reply_map(active: NostrEvent, events: [NostrEvent]) -> [String: ()]
+{
+ let event_map: [String: Int] = zip(events,0...events.count).reduce(into: [:]) { (acc, arg1) in
+ let (ev, i) = arg1
+ acc[ev.id] = i
+ }
+ var is_reply: [String: ()] = [:]
+ var i: Int = 0
+ var start: Int = 0
+ var iterations: Int = 0
+
+ if events.count == 0 {
+ return is_reply
+ }
+
+ for ev in events {
+ if ev.references(id: active.id, key: "e") {
+ is_reply[ev.id] = ()
+ start = i
+ } else if active.references(id: ev.id, key: "e") {
+ is_reply[ev.id] = ()
+ start = i
+ }
+ i += 1
+ }
+
+ i = start
+
+ while true {
+ if iterations > 1024 {
+ // infinite loop? or super large thread
+ print("breaking from large reply_map... big thread??")
+ break
+ }
+
+ let ev = events[i]
+
+ let ref_ids = ev.referenced_ids
+ if ref_ids.count == 0 {
+ break
+ }
+
+ let ref_id = ref_ids[ref_ids.count-1]
+ let pubkey = ref_id.ref_id
+ is_reply[pubkey] = ()
+
+ if let mi = event_map[pubkey] {
+ i = mi
+ } else {
+ break
+ }
+
+ iterations += 1
+ }
+
+ return is_reply
+}
+
func determine_highlight(current: NostrEvent, active: NostrEvent) -> Highlight
{
if current.id == active.id {
return .main
}
if active.references(id: current.id, key: "e") {
- return .replied_to(active.id)
+ return .reply
} else if current.references(id: active.id, key: "e") {
- return .replied_to(current.id)
+ return .reply
}
return .none
}
func calculated_collapsed_events(collapsed: Bool, active: NostrEvent, events: [NostrEvent]) -> [CollapsedEvent] {
var count: Int = 0
-
+
if !collapsed {
return events.reduce(into: []) { acc, ev in
let highlight = determine_highlight(current: ev, active: active)
return acc.append(.event(ev, highlight))
}
}
-
+
+ let reply_map = make_reply_map(active: active, events: events)
+
let nevents = events.count
var i: Int = 0
return events.reduce(into: []) { (acc, ev) in
- let highlight = determine_highlight(current: ev, active: active)
-
+ var highlight: Highlight = .none
+ if ev.id == active.id {
+ highlight = .main
+ } else if reply_map[ev.id] != nil {
+ highlight = .reply
+ }
+
switch highlight {
case .none:
count += 1
@@ -203,21 +269,21 @@ func calculated_collapsed_events(collapsed: Bool, active: NostrEvent, events: [N
count = 0
}
acc.append(.event(ev, .main))
- case .replied_to:
+ case .reply:
if count != 0 {
acc.append(.collapsed(count, UUID().description))
count = 0
}
acc.append(.event(ev, highlight))
}
-
+
if i == nevents-1 {
if count != 0 {
acc.append(.collapsed(count, UUID().description))
count = 0
}
}
-
+
i += 1
}
}
diff --git a/damus/Views/EventView.swift b/damus/Views/EventView.swift
@@ -12,7 +12,7 @@ import CachedAsyncImage
enum Highlight {
case none
case main
- case replied_to(String)
+ case reply
var is_none: Bool {
switch self {
@@ -23,7 +23,7 @@ enum Highlight {
var is_replied_to: Bool {
switch self {
- case .replied_to: return true
+ case .reply: return true
default: return false
}
}
diff --git a/damus/Views/ProfilePicView.swift b/damus/Views/ProfilePicView.swift
@@ -19,7 +19,7 @@ func highlight_color(_ h: Highlight) -> Color {
switch h {
case .none: return Color.black
case .main: return Color.red
- case .replied_to: return Color.blue
+ case .reply: return Color.blue
}
}