Relay Filters
wip
This commit is contained in:
@@ -7,119 +7,10 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CollapsedEvents: Identifiable {
|
||||
let count: Int
|
||||
let start: Int
|
||||
let end: Int
|
||||
|
||||
var id: String = UUID().description
|
||||
}
|
||||
|
||||
enum CollapsedEvent: Identifiable {
|
||||
case event(NostrEvent, Highlight)
|
||||
case collapsed(CollapsedEvents)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case .event(let ev, _):
|
||||
return ev.id
|
||||
case .collapsed(let c):
|
||||
return c.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct EventDetailView: View {
|
||||
let sub_id = UUID().description
|
||||
let damus: DamusState
|
||||
|
||||
@StateObject var thread: ThreadModel
|
||||
@State var collapsed: Bool = true
|
||||
|
||||
func toggle_collapse_thread(scroller: ScrollViewProxy, id mid: String?, animate: Bool = true) {
|
||||
self.collapsed = !self.collapsed
|
||||
if let id = mid {
|
||||
if !self.collapsed {
|
||||
scroll_to_event(scroller: scroller, id: id, delay: 0.1, animate: animate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func uncollapse_section(scroller: ScrollViewProxy, c: CollapsedEvents)
|
||||
{
|
||||
let ev = thread.events[c.start]
|
||||
print("uncollapsing section at \(c.start) '\(ev.content.prefix(12))...'")
|
||||
let start_id = ev.id
|
||||
|
||||
toggle_collapse_thread(scroller: scroller, id: start_id, animate: false)
|
||||
}
|
||||
|
||||
func CollapsedEventView(_ cev: CollapsedEvent, scroller: ScrollViewProxy) -> some View {
|
||||
Group {
|
||||
switch cev {
|
||||
case .collapsed(let c):
|
||||
Text(String(format: NSLocalizedString("collapsed_event_view_other_notes", comment: "Text to indicate that the thread was collapsed and that there are other notes to view if tapped."), c.count))
|
||||
.padding([.top,.bottom], 8)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
.onTapGesture {
|
||||
//self.uncollapse_section(scroller: proxy, c: c)
|
||||
//self.toggle_collapse_thread(scroller: proxy, id: nil)
|
||||
if let ev = thread.events[safe: c.start] {
|
||||
thread.set_active_event(ev, privkey: damus.keypair.privkey)
|
||||
}
|
||||
toggle_thread_view()
|
||||
}
|
||||
case .event(let ev, _):
|
||||
EventView(damus: damus, event: ev, has_action_bar: true)
|
||||
.onTapGesture {
|
||||
if thread.initial_event.id == ev.id {
|
||||
toggle_thread_view()
|
||||
} else {
|
||||
thread.set_active_event(ev, privkey: damus.keypair.privkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ScrollViewReader { proxy in
|
||||
if thread.loading {
|
||||
ProgressView().progressViewStyle(.circular)
|
||||
}
|
||||
|
||||
ScrollView(.vertical) {
|
||||
LazyVStack {
|
||||
let collapsed_events = calculated_collapsed_events(
|
||||
privkey: damus.keypair.privkey,
|
||||
collapsed: self.collapsed,
|
||||
active: thread.event,
|
||||
events: thread.events
|
||||
)
|
||||
ForEach(collapsed_events, id: \.id) { cev in
|
||||
CollapsedEventView(cev, scroller: proxy)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.top)
|
||||
|
||||
EndBlock()
|
||||
}
|
||||
.onChange(of: thread.loading) { val in
|
||||
scroll_after_load(thread: thread, proxy: proxy)
|
||||
}
|
||||
.onAppear() {
|
||||
scroll_after_load(thread: thread, proxy: proxy)
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(NSLocalizedString("Thread", comment: "Navigation bar title for note thread."))
|
||||
|
||||
}
|
||||
|
||||
func toggle_thread_view() {
|
||||
NotificationCenter.default.post(name: .toggle_thread_view, object: nil)
|
||||
Text("EventDetailView")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,167 +21,13 @@ func scroll_after_load(thread: ThreadModel, proxy: ScrollViewProxy) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct EventDetailView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let state = test_damus_state()
|
||||
let tm = ThreadModel(evid: "4da698ceac09a16cdb439276fa3d13ef8f6620ffb45d11b76b3f103483c2d0b0", damus_state: state)
|
||||
EventDetailView(damus: state, thread: tm)
|
||||
EventDetailView()
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the entire reply path for the active event
|
||||
func make_reply_map(active: NostrEvent, events: [NostrEvent], privkey: String?) -> [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 {
|
||||
/// does this event reply to the active event?
|
||||
let ev_refs = ev.event_refs(privkey)
|
||||
for ev_ref in ev_refs {
|
||||
if let reply = ev_ref.is_reply {
|
||||
if reply.ref_id == active.id {
|
||||
is_reply[ev.id] = ()
|
||||
start = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// does the active event reply to this event?
|
||||
let active_refs = active.event_refs(privkey)
|
||||
for active_ref in active_refs {
|
||||
if let reply = active_ref.is_reply {
|
||||
if reply.ref_id == ev.id {
|
||||
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(reply_map: [String: ()], current: NostrEvent, active: NostrEvent) -> Highlight
|
||||
{
|
||||
if current.id == active.id {
|
||||
return .main
|
||||
} else if reply_map[current.id] != nil {
|
||||
return .reply
|
||||
} else {
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
func calculated_collapsed_events(privkey: String?, collapsed: Bool, active: NostrEvent?, events: [NostrEvent]) -> [CollapsedEvent] {
|
||||
var count: Int = 0
|
||||
|
||||
guard let active = active else {
|
||||
return []
|
||||
}
|
||||
|
||||
let reply_map = make_reply_map(active: active, events: events, privkey: privkey)
|
||||
|
||||
if !collapsed {
|
||||
return events.reduce(into: []) { acc, ev in
|
||||
let highlight = determine_highlight(reply_map: reply_map, current: ev, active: active)
|
||||
return acc.append(.event(ev, highlight))
|
||||
}
|
||||
}
|
||||
|
||||
let nevents = events.count
|
||||
var start: Int = 0
|
||||
var i: Int = 0
|
||||
|
||||
return events.reduce(into: []) { (acc, ev) in
|
||||
let highlight = determine_highlight(reply_map: reply_map, current: ev, active: active)
|
||||
|
||||
switch highlight {
|
||||
case .none:
|
||||
if i == 0 {
|
||||
start = 1
|
||||
}
|
||||
count += 1
|
||||
case .main: fallthrough
|
||||
case .custom: fallthrough
|
||||
case .reply:
|
||||
if count != 0 {
|
||||
let c = CollapsedEvents(count: count, start: start, end: i)
|
||||
acc.append(.collapsed(c))
|
||||
start = i
|
||||
count = 0
|
||||
}
|
||||
acc.append(.event(ev, highlight))
|
||||
}
|
||||
|
||||
if i == nevents-1 {
|
||||
if count != 0 {
|
||||
let c = CollapsedEvents(count: count, start: i-count, end: i)
|
||||
acc.append(.collapsed(c))
|
||||
count = 0
|
||||
}
|
||||
}
|
||||
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func any_collapsed(_ evs: [CollapsedEvent]) -> Bool {
|
||||
for ev in evs {
|
||||
switch ev {
|
||||
case .collapsed:
|
||||
return true
|
||||
case .event:
|
||||
continue
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
func print_event(_ ev: NostrEvent) {
|
||||
print(ev.description)
|
||||
|
||||
Reference in New Issue
Block a user