integrate new threads conception

Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
kernelkind
2025-06-17 12:49:09 -04:00
parent f6753bae97
commit d560e84eab
10 changed files with 260 additions and 185 deletions

View File

@@ -3,21 +3,19 @@ use egui_virtual_list::VirtualList;
use enostr::KeypairUnowned;
use nostrdb::{Note, Transaction};
use notedeck::note::root_note_id_from_selected_id;
use notedeck::{MuteFun, NoteAction, NoteContext, RootNoteId, UnknownIds};
use notedeck::{MuteFun, NoteAction, NoteContext, UnknownIds};
use notedeck_ui::jobs::JobsCache;
use notedeck_ui::note::NoteResponse;
use notedeck_ui::{NoteOptions, NoteView};
use tracing::error;
use crate::timeline::thread::NoteSeenFlags;
use crate::timeline::{ThreadSelection, TimelineCache, TimelineKind};
use crate::ui::timeline::TimelineTabView;
use crate::timeline::thread::{NoteSeenFlags, ParentState, Threads};
pub struct ThreadView<'a, 'd> {
timeline_cache: &'a mut TimelineCache,
threads: &'a mut Threads,
unknown_ids: &'a mut UnknownIds,
selected_note_id: &'a [u8; 32],
note_options: NoteOptions,
col: usize,
id_source: egui::Id,
is_muted: &'a MuteFun,
note_context: &'a mut NoteContext<'d>,
@@ -28,7 +26,7 @@ pub struct ThreadView<'a, 'd> {
impl<'a, 'd> ThreadView<'a, 'd> {
#[allow(clippy::too_many_arguments)]
pub fn new(
timeline_cache: &'a mut TimelineCache,
threads: &'a mut Threads,
unknown_ids: &'a mut UnknownIds,
selected_note_id: &'a [u8; 32],
note_options: NoteOptions,
@@ -39,7 +37,7 @@ impl<'a, 'd> ThreadView<'a, 'd> {
) -> Self {
let id_source = egui::Id::new("threadscroll_threadview");
ThreadView {
timeline_cache,
threads,
unknown_ids,
selected_note_id,
note_options,
@@ -48,11 +46,13 @@ impl<'a, 'd> ThreadView<'a, 'd> {
note_context,
cur_acc,
jobs,
col: 0,
}
}
pub fn id_source(mut self, id: egui::Id) -> Self {
self.id_source = id;
pub fn id_source(mut self, col: usize) -> Self {
self.col = col;
self.id_source = egui::Id::new(("threadscroll", col));
self
}
@@ -73,62 +73,88 @@ impl<'a, 'd> ThreadView<'a, 'd> {
scroll_area = scroll_area.vertical_scroll_offset(offset);
}
let output = scroll_area.show(ui, |ui| {
let root_id = match RootNoteId::new(
self.note_context.ndb,
self.note_context.note_cache,
&txn,
self.selected_note_id,
) {
Ok(root_id) => root_id,
Err(err) => {
ui.label(format!("Error loading thread: {:?}", err));
return None;
}
};
let thread_timeline = self
.timeline_cache
.notes(
self.note_context.ndb,
self.note_context.note_cache,
&txn,
&TimelineKind::Thread(ThreadSelection::from_root_id(root_id.to_owned())),
)
.get_ptr();
// TODO(jb55): skip poll if ThreadResult is fresh?
let reversed = true;
// poll for new notes and insert them into our existing notes
if let Err(err) = thread_timeline.poll_notes_into_view(
self.note_context.ndb,
&txn,
self.unknown_ids,
self.note_context.note_cache,
reversed,
) {
error!("error polling notes into thread timeline: {err}");
}
TimelineTabView::new(
thread_timeline.current_view(),
true,
self.note_options,
&txn,
self.is_muted,
self.note_context,
self.cur_acc,
self.jobs,
)
.show(ui)
});
let output = scroll_area.show(ui, |ui| self.notes(ui, &txn));
ui.data_mut(|d| d.insert_temp(offset_id, output.state.offset.y));
output.inner
}
fn notes(&mut self, ui: &mut egui::Ui, txn: &Transaction) -> Option<NoteAction> {
let Ok(cur_note) = self
.note_context
.ndb
.get_note_by_id(txn, self.selected_note_id)
else {
let id = *self.selected_note_id;
tracing::error!("ndb: Did not find note {}", enostr::NoteId::new(id).hex());
return None;
};
self.threads.update(
&cur_note,
self.note_context.note_cache,
self.note_context.ndb,
txn,
self.unknown_ids,
self.col,
);
let cur_node = self.threads.threads.get(&self.selected_note_id).unwrap();
let full_chain = cur_node.have_all_ancestors;
let mut note_builder = ThreadNoteBuilder::new(cur_note);
let mut parent_state = cur_node.prev.clone();
while let ParentState::Parent(id) = parent_state {
if let Ok(note) = self.note_context.ndb.get_note_by_id(txn, id.bytes()) {
note_builder.add_chain(note);
if let Some(res) = self.threads.threads.get(&id.bytes()) {
parent_state = res.prev.clone();
continue;
}
}
parent_state = ParentState::Unknown;
}
for note_ref in &cur_node.replies {
if let Ok(note) = self.note_context.ndb.get_note_by_key(txn, note_ref.key) {
note_builder.add_reply(note);
}
}
let list = &mut self
.threads
.threads
.get_mut(&self.selected_note_id)
.unwrap()
.list;
let notes = note_builder.into_notes(&mut self.threads.seen_flags);
if !full_chain {
// TODO(kernelkind): insert UI denoting we don't have the full chain yet
ui.colored_label(ui.visuals().error_fg_color, "LOADING NOTES");
}
let zapping_acc = self
.cur_acc
.as_ref()
.filter(|_| self.note_context.current_account_has_wallet)
.or(self.cur_acc.as_ref());
show_notes(
ui,
list,
&notes,
self.note_context,
zapping_acc,
self.note_options,
self.jobs,
txn,
self.is_muted,
)
}
}
#[allow(clippy::too_many_arguments)]