notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 2b20f7397481aa0838c6b7586f3cc00a873b065a
parent d4ccf7435f1d25e0f8a1252461d4c83230f21d71
Author: William Casarin <jb55@jb55.com>
Date:   Fri, 12 Apr 2024 18:53:32 -0700

initial inline note previews

still needs a border and options to remove actionbar

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Msrc/ui/note/contents.rs | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/ui/note/mod.rs | 41+++++++++++++++++++++--------------------
2 files changed, 83 insertions(+), 41 deletions(-)

diff --git a/src/ui/note/contents.rs b/src/ui/note/contents.rs @@ -1,5 +1,5 @@ -use crate::{colors, Damus}; -use egui::{Hyperlink, Image, RichText}; +use crate::{colors, ui, Damus}; +use egui::{Color32, Hyperlink, Image, RichText}; use nostrdb::{BlockType, Mention, Note, NoteKey, Transaction}; use tracing::warn; @@ -32,6 +32,31 @@ impl egui::Widget for NoteContents<'_> { } } +fn render_note_preview( + ui: &mut egui::Ui, + app: &mut Damus, + txn: &Transaction, + id: &[u8; 32], + _id_str: &str, +) -> egui::Response { + let note = if let Ok(note) = app.ndb.get_note_by_id(txn, id) { + note + } else { + return ui.colored_label(Color32::RED, "TODO: COULD NOT LOAD"); + /* + return ui + .horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 0.0; + ui.colored_label(colors::PURPLE, "@"); + ui.colored_label(colors::PURPLE, &id_str[4..16]); + }) + .response; + */ + }; + + ui.add(ui::Note::new(app, &note).actionbar(false)) +} + fn render_note_contents( ui: &mut egui::Ui, damus: &mut Damus, @@ -43,6 +68,7 @@ fn render_note_contents( puffin::profile_function!(); let images: Vec<String> = vec![]; + let mut inline_note: Option<(&[u8; 32], &str)> = None; let resp = ui.horizontal_wrapped(|ui| { let blocks = if let Ok(blocks) = damus.ndb.get_blocks_by_key(txn, note_key) { @@ -57,29 +83,40 @@ fn render_note_contents( for block in blocks.iter(note) { match block.blocktype() { - BlockType::MentionBech32 => { - ui.colored_label(colors::PURPLE, "@"); - match block.as_mention().unwrap() { - Mention::Pubkey(npub) => { - let profile = damus.ndb.get_profile_by_pubkey(txn, npub.pubkey()).ok(); - if let Some(name) = profile - .as_ref() - .and_then(|p| crate::profile::get_profile_name(p)) - { - ui.colored_label(colors::PURPLE, name); - } else { - ui.colored_label(colors::PURPLE, "nostrich"); - } - } - _ => { - ui.colored_label(colors::PURPLE, block.as_str()); + BlockType::MentionBech32 => match block.as_mention().unwrap() { + Mention::Pubkey(npub) => { + ui.colored_label(colors::PURPLE, "@"); + let profile = damus.ndb.get_profile_by_pubkey(txn, npub.pubkey()).ok(); + if let Some(name) = profile + .as_ref() + .and_then(|p| crate::profile::get_profile_name(p)) + { + ui.colored_label(colors::PURPLE, name); + } else { + ui.colored_label(colors::PURPLE, "nostrich"); } } - } + + Mention::Note(note) => { + inline_note = Some((note.id(), block.as_str())); + } + + Mention::Event(note) => { + inline_note = Some((note.id(), block.as_str())); + } + + _ => { + ui.colored_label(colors::PURPLE, "@"); + ui.colored_label(colors::PURPLE, &block.as_str()[4..16]); + } + }, BlockType::Hashtag => { - ui.colored_label(colors::PURPLE, "#"); - ui.colored_label(colors::PURPLE, block.as_str()); + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 0.0; + ui.colored_label(colors::PURPLE, "#"); + ui.colored_label(colors::PURPLE, block.as_str()); + }); } BlockType::Url => { @@ -107,6 +144,10 @@ fn render_note_contents( } }); + if let Some((id, block_str)) = inline_note { + render_note_preview(ui, damus, txn, id, block_str); + } + for image in images { let img_resp = ui.add(Image::new(image.clone())); img_resp.context_menu(|ui| { diff --git a/src/ui/note/mod.rs b/src/ui/note/mod.rs @@ -3,18 +3,11 @@ pub use contents::NoteContents; use crate::{ui, Damus}; use egui::{Color32, Label, RichText, Sense, TextureHandle, Vec2}; -use nostrdb::NoteKey; pub struct Note<'a> { app: &'a mut Damus, note: &'a nostrdb::Note<'a>, - timeline: usize, -} - -#[derive(Hash, Clone, Copy)] -struct NoteTimelineKey { - timeline: usize, - note_key: NoteKey, + actionbar: bool, } impl<'a> egui::Widget for Note<'a> { @@ -28,14 +21,20 @@ impl<'a> egui::Widget for Note<'a> { } impl<'a> Note<'a> { - pub fn new(app: &'a mut Damus, note: &'a nostrdb::Note<'a>, timeline: usize) -> Self { + pub fn new(app: &'a mut Damus, note: &'a nostrdb::Note<'a>) -> Self { + let actionbar = true; Note { app, note, - timeline, + actionbar, } } + pub fn actionbar(mut self, enable: bool) -> Self { + self.actionbar = enable; + self + } + fn textmode_ui(self, ui: &mut egui::Ui) -> egui::Response { let note_key = self.note.key().expect("todo: implement non-db notes"); let txn = self.note.txn().expect("todo: implement non-db notes"); @@ -76,20 +75,20 @@ impl<'a> Note<'a> { puffin::profile_function!(); let note_key = self.note.key().expect("todo: support non-db notes"); let txn = self.note.txn().expect("todo: support non-db notes"); - let timeline = self.timeline; - let id = egui::Id::new(NoteTimelineKey { note_key, timeline }); ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { let profile = self.app.ndb.get_profile_by_pubkey(txn, self.note.pubkey()); + /* let mut collapse_state = egui::collapsing_header::CollapsingState::load_with_default_open( ui.ctx(), id, false, ); + */ - let inner_resp = crate::ui::padding(6.0, ui, |ui| { + crate::ui::padding(6.0, ui, |ui| { match profile .as_ref() .ok() @@ -117,19 +116,21 @@ impl<'a> Note<'a> { ui.add(NoteContents::new(self.app, txn, self.note, note_key)); - render_note_actionbar(ui); + if self.actionbar { + render_note_actionbar(ui); + } //let header_res = ui.horizontal(|ui| {}); }); }); - let resp = ui.interact(inner_resp.response.rect, id, Sense::hover()); + //let resp = ui.interact(inner_resp.response.rect, id, Sense::hover()); - if resp.hovered() ^ collapse_state.is_open() { - //info!("clicked {:?}, {}", self.note_key, collapse_state.is_open()); - collapse_state.toggle(ui); - collapse_state.store(ui.ctx()); - } + //if resp.hovered() ^ collapse_state.is_open() { + //info!("clicked {:?}, {}", self.note_key, collapse_state.is_open()); + //collapse_state.toggle(ui); + //collapse_state.store(ui.ctx()); + //} }) .response }