use crate::{ note::NoteRef, notecache::NoteCache, notes_holder::{NotesHolder, NotesHolderStorage}, route::{Route, Router}, thread::Thread, }; use enostr::{NoteId, Pubkey, RelayPool}; use nostrdb::{Ndb, Transaction}; #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum BarAction { Reply(NoteId), Quote(NoteId), OpenThread(NoteId), } #[derive(Default)] pub struct NoteActionResponse { pub bar_action: Option, pub open_profile: Option, } pub struct NewNotes { pub id: [u8; 32], pub notes: Vec, } pub enum NotesHolderResult { NewNotes(NewNotes), } /// open_thread is called when a note is selected and we need to navigate /// to a thread It is responsible for managing the subscription and /// making sure the thread is up to date. In a sense, it's a model for /// the thread view. We don't have a concept of model/view/controller etc /// in egui, but this is the closest thing to that. fn open_thread( ndb: &Ndb, txn: &Transaction, router: &mut Router, note_cache: &mut NoteCache, pool: &mut RelayPool, threads: &mut NotesHolderStorage, selected_note: &[u8; 32], ) -> Option { router.route_to(Route::thread(NoteId::new(selected_note.to_owned()))); let root_id = crate::note::root_note_id_from_selected_id(ndb, note_cache, txn, selected_note); Thread::open(ndb, note_cache, txn, pool, threads, root_id) } impl BarAction { #[allow(clippy::too_many_arguments)] pub fn execute( self, ndb: &Ndb, router: &mut Router, threads: &mut NotesHolderStorage, note_cache: &mut NoteCache, pool: &mut RelayPool, txn: &Transaction, ) -> Option { match self { BarAction::Reply(note_id) => { router.route_to(Route::reply(note_id)); router.navigating = true; None } BarAction::OpenThread(note_id) => { open_thread(ndb, txn, router, note_cache, pool, threads, note_id.bytes()) } BarAction::Quote(note_id) => { router.route_to(Route::quote(note_id)); router.navigating = true; None } } } /// Execute the BarAction and process the BarResult pub fn execute_and_process_result( self, ndb: &Ndb, router: &mut Router, threads: &mut NotesHolderStorage, note_cache: &mut NoteCache, pool: &mut RelayPool, txn: &Transaction, ) { if let Some(br) = self.execute(ndb, router, threads, note_cache, pool, txn) { br.process(ndb, note_cache, txn, threads); } } } impl NotesHolderResult { pub fn new_notes(notes: Vec, id: [u8; 32]) -> Self { NotesHolderResult::NewNotes(NewNotes::new(notes, id)) } pub fn process( &self, ndb: &Ndb, note_cache: &mut NoteCache, txn: &Transaction, storage: &mut NotesHolderStorage, ) { match self { // update the thread for next render if we have new notes NotesHolderResult::NewNotes(new_notes) => { let holder = storage .notes_holder_mutated(ndb, note_cache, txn, &new_notes.id) .get_ptr(); new_notes.process(holder); } } } } impl NewNotes { pub fn new(notes: Vec, id: [u8; 32]) -> Self { NewNotes { notes, id } } /// Simple helper for processing a NewThreadNotes result. It simply /// inserts/merges the notes into the thread cache pub fn process(&self, thread: &mut N) { // threads are chronological, ie reversed from reverse-chronological, the default. let reversed = true; thread.get_view().insert(&self.notes, reversed); } }