diff --git a/src/app.rs b/src/app.rs index 8e46e811..cd4d6a6b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,4 +1,5 @@ use crate::abbrev; +use crate::colors; use crate::error::Error; use crate::fonts::{setup_fonts, NamedFontFamily}; use crate::frame_history::FrameHistory; @@ -7,6 +8,7 @@ use crate::imgcache::ImageCache; use crate::notecache::NoteCache; use crate::timeline; use crate::ui::padding; +use crate::widgets::note::NoteContents; use crate::Result; use egui::containers::scroll_area::ScrollBarVisibility; use std::borrow::Cow; @@ -32,9 +34,6 @@ use tracing::{debug, error, info, warn}; use enostr::RelayPool; -const PURPLE: Color32 = Color32::from_rgb(0xCC, 0x43, 0xC5); -const DARK_BG: Color32 = egui::Color32::from_rgb(40, 44, 52); - #[derive(Debug, Eq, PartialEq, Clone)] pub enum DamusState { Initializing, @@ -615,105 +614,6 @@ fn render_notes_in_viewport( ui.allocate_rect(used_rect, egui::Sense::hover()); // make sure it is visible! } -fn get_profile_name<'a>(record: &'a ProfileRecord) -> Option<&'a str> { - let profile = record.record.profile()?; - let display_name = profile.display_name(); - let name = profile.name(); - - if display_name.is_some() && display_name.unwrap() != "" { - return display_name; - } - - if name.is_some() && name.unwrap() != "" { - return name; - } - - None -} - -fn render_note_contents( - ui: &mut egui::Ui, - damus: &mut Damus, - txn: &Transaction, - note: &Note, - note_key: NoteKey, -) { - #[cfg(feature = "profiling")] - puffin::profile_function!(); - - let mut images: Vec = vec![]; - - ui.horizontal_wrapped(|ui| { - let blocks = if let Ok(blocks) = damus.ndb.get_blocks_by_key(txn, note_key) { - blocks - } else { - warn!("missing note content blocks? '{}'", note.content()); - ui.weak(note.content()); - return; - }; - - ui.spacing_mut().item_spacing.x = 0.0; - - for block in blocks.iter(note) { - match block.blocktype() { - BlockType::MentionBech32 => { - ui.colored_label(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| get_profile_name(p)) { - ui.colored_label(PURPLE, name); - } else { - ui.colored_label(PURPLE, "nostrich"); - } - } - _ => { - ui.colored_label(PURPLE, block.as_str()); - } - } - } - - BlockType::Hashtag => { - ui.colored_label(PURPLE, "#"); - ui.colored_label(PURPLE, block.as_str()); - } - - BlockType::Url => { - /* - let url = block.as_str().to_lowercase(); - if url.ends_with("png") || url.ends_with("jpg") { - images.push(url); - } else { - */ - ui.add(Hyperlink::from_label_and_url( - RichText::new(block.as_str()).color(PURPLE), - block.as_str(), - )); - //} - } - - BlockType::Text => { - ui.label(block.as_str()); - } - - _ => { - ui.colored_label(PURPLE, block.as_str()); - } - } - } - }); - - for image in images { - let resp = ui.add(Image::new(image.clone())); - resp.context_menu(|ui| { - if ui.button("Copy Link").clicked() { - ui.ctx().copy_text(image); - ui.close_menu(); - } - }); - } -} - fn render_reltime(ui: &mut egui::Ui, note_cache: &mut NoteCache) { #[cfg(feature = "profiling")] puffin::profile_function!(); @@ -781,18 +681,32 @@ fn render_note( render_reltime(ui, note_cache); }); - render_note_contents(ui, damus, &txn, ¬e, note_key); + let note_sidebar_size = 20.0; + + ui.horizontal(|ui| { + let mut size = ui.available_size(); + size.x -= note_sidebar_size; + + let contents = NoteContents::new(damus, &txn, ¬e, note_key); + //let resp = render_note_contents(ui, damus, &txn, ¬e, note_key); + //ui.allocate_space() + // + ui.add_sized(size, contents); + + collapse_state.show_body_unindented(ui, |ui| { + ui.set_width(note_sidebar_size); + render_note_actionbar(ui) + }); + }); //let header_res = ui.horizontal(|ui| {}); - - collapse_state.show_body_unindented(ui, |ui| render_note_actionbar(ui)); }); }); let resp = ui.interact(inner_resp.response.rect, id, Sense::hover()); if resp.hovered() ^ collapse_state.is_open() { - info!("clicked {:?}, {}", note_key, collapse_state.is_open()); + //info!("clicked {:?}, {}", note_key, collapse_state.is_open()); collapse_state.toggle(ui); collapse_state.store(ui.ctx()); } @@ -802,7 +716,7 @@ fn render_note( } fn render_note_actionbar(ui: &mut egui::Ui) -> egui::InnerResponse<()> { - ui.horizontal(|ui| { + ui.vertical(|ui| { if ui .add( egui::Button::image(egui::Image::new(egui::include_image!( @@ -916,7 +830,7 @@ fn render_panel<'a>(ctx: &egui::Context, app: &'a mut Damus, timeline_ind: usize fn set_app_style(style: &mut Style) { let visuals = &mut style.visuals; - visuals.hyperlink_color = PURPLE; + visuals.hyperlink_color = colors::PURPLE; if visuals.dark_mode { visuals.override_text_color = Some(egui::Color32::from_rgb(250, 250, 250)); //visuals.panel_fill = egui::Color32::from_rgb(31, 31, 31); diff --git a/src/colors.rs b/src/colors.rs new file mode 100644 index 00000000..76454506 --- /dev/null +++ b/src/colors.rs @@ -0,0 +1,4 @@ +use egui::Color32; + +pub const PURPLE: Color32 = Color32::from_rgb(0xCC, 0x43, 0xC5); +pub const DARK_BG: Color32 = egui::Color32::from_rgb(40, 44, 52); diff --git a/src/lib.rs b/src/lib.rs index 0cf8e46d..15a1f00b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ mod error; //mod note; //mod block; mod abbrev; +mod widgets; mod fonts; mod images; mod result; @@ -15,6 +16,8 @@ mod time; mod notecache; mod frame_history; mod timeline; +mod colors; +mod profile; pub use app::Damus; pub use error::Error; diff --git a/src/profile.rs b/src/profile.rs new file mode 100644 index 00000000..ac03603d --- /dev/null +++ b/src/profile.rs @@ -0,0 +1,17 @@ +use nostrdb::ProfileRecord; + +pub fn get_profile_name<'a>(record: &'a ProfileRecord) -> Option<&'a str> { + let profile = record.record.profile()?; + let display_name = profile.display_name(); + let name = profile.name(); + + if display_name.is_some() && display_name.unwrap() != "" { + return display_name; + } + + if name.is_some() && name.unwrap() != "" { + return name; + } + + None +} diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs new file mode 100644 index 00000000..f20ccb59 --- /dev/null +++ b/src/widgets/mod.rs @@ -0,0 +1 @@ +pub mod note; diff --git a/src/widgets/note/contents.rs b/src/widgets/note/contents.rs new file mode 100644 index 00000000..f85129a2 --- /dev/null +++ b/src/widgets/note/contents.rs @@ -0,0 +1,121 @@ +use crate::{colors, Damus}; +use egui::{Hyperlink, Image, RichText}; +use nostrdb::{BlockType, Mention, Note, NoteKey, Transaction}; +use tracing::warn; + +pub struct NoteContents<'a> { + damus: &'a mut Damus, + txn: &'a Transaction, + note: &'a Note<'a>, + note_key: NoteKey, +} + +impl<'a> NoteContents<'a> { + pub fn new( + damus: &'a mut Damus, + txn: &'a Transaction, + note: &'a Note, + note_key: NoteKey, + ) -> Self { + NoteContents { + damus, + txn, + note, + note_key, + } + } +} + +impl egui::Widget for NoteContents<'_> { + fn ui(self, ui: &mut egui::Ui) -> egui::Response { + render_note_contents(ui, self.damus, self.txn, self.note, self.note_key).response + } +} + +fn render_note_contents( + ui: &mut egui::Ui, + damus: &mut Damus, + txn: &Transaction, + note: &Note, + note_key: NoteKey, +) -> egui::InnerResponse<()> { + #[cfg(feature = "profiling")] + puffin::profile_function!(); + + let mut images: Vec = vec![]; + + let resp = ui.horizontal_wrapped(|ui| { + let blocks = if let Ok(blocks) = damus.ndb.get_blocks_by_key(txn, note_key) { + blocks + } else { + warn!("missing note content blocks? '{}'", note.content()); + ui.weak(note.content()); + return; + }; + + ui.spacing_mut().item_spacing.x = 0.0; + + 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::Hashtag => { + ui.colored_label(colors::PURPLE, "#"); + ui.colored_label(colors::PURPLE, block.as_str()); + } + + BlockType::Url => { + /* + let url = block.as_str().to_lowercase(); + if url.ends_with("png") || url.ends_with("jpg") { + images.push(url); + } else { + */ + ui.add(Hyperlink::from_label_and_url( + RichText::new(block.as_str()).color(colors::PURPLE), + block.as_str(), + )); + //} + } + + BlockType::Text => { + ui.label(block.as_str()); + } + + _ => { + ui.colored_label(colors::PURPLE, block.as_str()); + } + } + } + }); + + for image in images { + let img_resp = ui.add(Image::new(image.clone())); + img_resp.context_menu(|ui| { + if ui.button("Copy Link").clicked() { + ui.ctx().copy_text(image); + ui.close_menu(); + } + }); + } + + resp +} diff --git a/src/widgets/note/mod.rs b/src/widgets/note/mod.rs new file mode 100644 index 00000000..f30b0784 --- /dev/null +++ b/src/widgets/note/mod.rs @@ -0,0 +1,3 @@ +pub mod contents; + +pub use contents::NoteContents;