diff --git a/src/ui/thread.rs b/src/ui/thread.rs index a65881e..ae7c24e 100644 --- a/src/ui/thread.rs +++ b/src/ui/thread.rs @@ -1,9 +1,10 @@ use crate::{ - actionbar::{BarAction, TimelineResponse}, imgcache::ImageCache, notecache::NoteCache, thread::Threads, ui, + actionbar::TimelineResponse, imgcache::ImageCache, notecache::NoteCache, thread::Threads, }; -use enostr::Pubkey; use nostrdb::{Ndb, NoteKey, Transaction}; -use tracing::{error, warn}; +use tracing::error; + +use super::timeline::TimelineTabView; pub struct ThreadView<'a> { threads: &'a mut Threads, @@ -44,8 +45,6 @@ impl<'a> ThreadView<'a> { pub fn ui(&mut self, ui: &mut egui::Ui) -> TimelineResponse { let txn = Transaction::new(self.ndb).expect("txn"); - let mut action: Option = None; - let mut open_profile = None; let selected_note_key = if let Ok(key) = self .ndb @@ -72,7 +71,7 @@ impl<'a> ThreadView<'a> { let note = if let Ok(note) = self.ndb.get_note_by_key(&txn, selected_note_key) { note } else { - return; + return TimelineResponse::default(); }; let root_id = { @@ -96,56 +95,17 @@ impl<'a> ThreadView<'a> { error!("Thread::poll_notes_into_view: {e}"); } - let len = thread.view().notes.len(); - - thread.view().list.clone().borrow_mut().ui_custom_layout( - ui, - len, - |ui, start_index| { - ui.spacing_mut().item_spacing.y = 0.0; - ui.spacing_mut().item_spacing.x = 4.0; - - let ind = len - 1 - start_index; - - let note_key = thread.view().notes[ind].key; - - let note = if let Ok(note) = self.ndb.get_note_by_key(&txn, note_key) { - note - } else { - warn!("failed to query note {:?}", note_key); - return 0; - }; - - ui::padding(8.0, ui, |ui| { - let note_response = - ui::NoteView::new(self.ndb, self.note_cache, self.img_cache, ¬e) - .note_previews(!self.textmode) - .textmode(self.textmode) - .options_button(!self.textmode) - .show(ui); - if let Some(bar_action) = note_response.action { - action = Some(bar_action); - } - if note_response.clicked_profile { - open_profile = Some(Pubkey::new(*note.pubkey())) - } - - if let Some(selection) = note_response.context_selection { - selection.process(ui, ¬e); - } - }); - - ui::hline(ui); - //ui.add(egui::Separator::default().spacing(0.0)); - - 1 - }, - ); - }); - - TimelineResponse { - bar_action: action, - open_profile, - } + TimelineTabView::new( + thread.view(), + true, + self.textmode, + &txn, + self.ndb, + self.note_cache, + self.img_cache, + ) + .show(ui) + }) + .inner } } diff --git a/src/ui/timeline.rs b/src/ui/timeline.rs index cc8c972..d8951af 100644 --- a/src/ui/timeline.rs +++ b/src/ui/timeline.rs @@ -1,4 +1,5 @@ use crate::actionbar::TimelineResponse; +use crate::timeline::TimelineTab; use crate::{ actionbar::BarAction, column::Columns, imgcache::ImageCache, notecache::NoteCache, timeline::TimelineId, ui, @@ -144,9 +145,6 @@ fn timeline_ui_no_scroll( reversed: bool, textmode: bool, ) -> TimelineResponse { - let mut open_profile: Option = None; - let mut bar_action: Option = None; - let timeline = if let Some(timeline) = columns.find_timeline_mut(timeline_id) { timeline } else { @@ -156,70 +154,17 @@ fn timeline_ui_no_scroll( return TimelineResponse::default(); }; - let view = timeline.current_view(); - let len = view.notes.len(); - let txn = if let Ok(txn) = Transaction::new(ndb) { - txn - } else { - warn!("failed to create transaction"); - return TimelineResponse::default(); - }; - - view.list - .clone() - .borrow_mut() - .ui_custom_layout(ui, len, |ui, start_index| { - ui.spacing_mut().item_spacing.y = 0.0; - ui.spacing_mut().item_spacing.x = 4.0; - - let ind = if reversed { - len - start_index - 1 - } else { - start_index - }; - - let note_key = timeline.current_view().notes[ind].key; - - let note = if let Ok(note) = ndb.get_note_by_key(&txn, note_key) { - note - } else { - warn!("failed to query note {:?}", note_key); - return 0; - }; - - ui::padding(8.0, ui, |ui| { - let resp = ui::NoteView::new(ndb, note_cache, img_cache, ¬e) - .note_previews(!textmode) - .selectable_text(false) - .options_button(true) - .show(ui); - - if let Some(ba) = resp.action { - bar_action = Some(ba); - } else if resp.response.clicked() { - debug!("clicked note"); - } - - if let Some(context) = resp.context_selection { - context.process(ui, ¬e); - } - - if resp.clicked_profile { - info!("clicked profile"); - open_profile = Some(Pubkey::new(*note.pubkey())) - } - }); - - ui::hline(ui); - //ui.add(egui::Separator::default().spacing(0.0)); - - 1 - }); - - TimelineResponse { - open_profile, - bar_action, - } + let txn = Transaction::new(ndb).expect("failed to create txn"); + TimelineTabView::new( + timeline.current_view(), + reversed, + textmode, + &txn, + ndb, + note_cache, + img_cache, + ) + .show(ui) } fn tabs_ui(ui: &mut egui::Ui) -> i32 { @@ -305,3 +250,98 @@ fn shrink_range_to_width(range: egui::Rangef, width: f32) -> egui::Rangef { egui::Rangef::new(min, max) } + +pub struct TimelineTabView<'a> { + tab: &'a TimelineTab, + reversed: bool, + textmode: bool, + txn: &'a Transaction, + ndb: &'a Ndb, + note_cache: &'a mut NoteCache, + img_cache: &'a mut ImageCache, +} + +impl<'a> TimelineTabView<'a> { + pub fn new( + tab: &'a TimelineTab, + reversed: bool, + textmode: bool, + txn: &'a Transaction, + ndb: &'a Ndb, + note_cache: &'a mut NoteCache, + img_cache: &'a mut ImageCache, + ) -> Self { + Self { + tab, + reversed, + txn, + textmode, + ndb, + note_cache, + img_cache, + } + } + + pub fn show(&mut self, ui: &mut egui::Ui) -> TimelineResponse { + let mut open_profile = None; + let mut bar_action: Option = None; + let len = self.tab.notes.len(); + + self.tab + .list + .clone() + .borrow_mut() + .ui_custom_layout(ui, len, |ui, start_index| { + ui.spacing_mut().item_spacing.y = 0.0; + ui.spacing_mut().item_spacing.x = 4.0; + + let ind = if self.reversed { + len - start_index - 1 + } else { + start_index + }; + + let note_key = self.tab.notes[ind].key; + + let note = if let Ok(note) = self.ndb.get_note_by_key(self.txn, note_key) { + note + } else { + warn!("failed to query note {:?}", note_key); + return 0; + }; + + ui::padding(8.0, ui, |ui| { + let resp = ui::NoteView::new(self.ndb, self.note_cache, self.img_cache, ¬e) + .note_previews(!self.textmode) + .selectable_text(false) + .options_button(true) + .show(ui); + + if let Some(ba) = resp.action { + bar_action = Some(ba); + } else if resp.response.clicked() { + debug!("clicked note"); + } + + if let Some(context) = resp.context_selection { + context.process(ui, ¬e); + } + + if resp.clicked_profile { + info!("clicked profile"); + open_profile = Some(Pubkey::new(*note.pubkey())) + } + }); + + ui::hline(ui); + //ui.add(egui::Separator::default().spacing(0.0)); + + 1 + }); + + TimelineResponse { + open_profile, + bar_action, + } + } +}