notedeck

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

commit 9d1e8ce666e0215f338a18b0f44b33f67dcf9924
parent 7ecacc69a55d8a4c2071bfb3c38bad401ccbc56a
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 11 Apr 2024 11:09:30 -0700

irc mode

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

Diffstat:
Msrc/app.rs | 143+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/widgets/mod.rs | 1+
Asrc/widgets/username.rs | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 171 insertions(+), 50 deletions(-)

diff --git a/src/app.rs b/src/app.rs @@ -10,6 +10,7 @@ use crate::notecache::NoteCache; use crate::timeline; use crate::ui::padding; use crate::widgets::note::NoteContents; +use crate::widgets::username::Username; use crate::Result; use egui::containers::scroll_area::ScrollBarVisibility; @@ -84,6 +85,7 @@ pub struct Damus { //compose: String, note_cache: HashMap<NoteKey, NoteCache>, pool: RelayPool, + irc_mode: bool, timelines: Vec<Timeline>, @@ -450,6 +452,7 @@ impl Damus { img_cache: ImageCache::new(imgcache_dir), note_cache: HashMap::new(), timelines, + irc_mode: false, ndb: Ndb::new(data_path.as_ref().to_str().expect("db path ok"), &config).expect("ndb"), //compose: "".to_string(), frame_history: FrameHistory::default(), @@ -525,44 +528,6 @@ fn pfp_image<'a>(ui: &mut egui::Ui, img: &TextureHandle, size: f32) -> egui::Res //.with_options() } -fn ui_abbreviate_name(ui: &mut egui::Ui, name: &str, len: usize) { - if name.len() > len { - let closest = abbrev::floor_char_boundary(name, len); - ui.strong(&name[..closest]); - ui.strong("..."); - } else { - ui.add(Label::new( - RichText::new(name).family(NamedFontFamily::Medium.as_family()), - )); - } -} - -fn render_username(ui: &mut egui::Ui, profile: Option<&ProfileRecord>, _pk: &[u8; 32]) { - #[cfg(feature = "profiling")] - puffin::profile_function!(); - - ui.horizontal(|ui| { - //ui.spacing_mut().item_spacing.x = 0.0; - if let Some(profile) = profile { - if let Some(prof) = profile.record.profile() { - if prof.display_name().is_some() && prof.display_name().unwrap() != "" { - ui_abbreviate_name(ui, prof.display_name().unwrap(), 20); - } else if let Some(name) = prof.name() { - ui_abbreviate_name(ui, name, 20); - } - } - } else { - ui.strong("nostrich"); - } - - /* - ui.label(&pk.as_ref()[0..8]); - ui.label(":"); - ui.label(&pk.as_ref()[64 - 8..]); - */ - }); -} - fn no_pfp_url() -> &'static str { "https://damus.io/img/no-profile.svg" } @@ -609,17 +574,28 @@ fn render_notes_in_viewport( } */ -fn render_reltime(ui: &mut egui::Ui, note_cache: &mut NoteCache) { +fn render_reltime( + ui: &mut egui::Ui, + note_cache: &mut NoteCache, + before: bool, +) -> egui::InnerResponse<()> { #[cfg(feature = "profiling")] puffin::profile_function!(); - let color = Color32::from_rgb(0x8A, 0x8A, 0x8A); - ui.add(Label::new(RichText::new("⋅").size(10.0).color(color))); - ui.add(Label::new( - RichText::new(note_cache.reltime_str()) - .size(10.0) - .color(color), - )); + ui.horizontal(|ui| { + let color = Color32::from_rgb(0x8A, 0x8A, 0x8A); + if before { + ui.add(Label::new(RichText::new("⋅").size(10.0).color(color))); + } + ui.add(Label::new( + RichText::new(note_cache.reltime_str()) + .size(10.0) + .color(color), + )); + if !before { + ui.add(Label::new(RichText::new("⋅").size(10.0).color(color))); + } + }) } /* @@ -637,6 +613,61 @@ struct NoteTimelineKey { note_key: NoteKey, } +fn render_irc_note( + ui: &mut egui::Ui, + damus: &mut Damus, + note_key: NoteKey, + timeline: usize, +) -> Result<()> { + let txn = Transaction::new(&damus.ndb)?; + let note = damus.ndb.get_note_by_key(&txn, note_key)?; + let id = egui::Id::new(NoteTimelineKey { note_key, timeline }); + + ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { + let profile = damus.ndb.get_profile_by_pubkey(&txn, note.pubkey()); + + //ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 2.0; + + let note_cache = damus.get_note_cache_mut(note_key, note.created_at()); + let (_id, rect) = ui.allocate_space(egui::vec2(50.0, 20.0)); + ui.allocate_rect(rect, Sense::hover()); + ui.put(rect, |ui: &mut egui::Ui| { + ui.set_clip_rect(rect); + render_reltime(ui, note_cache, false).response + }); + let (_id, rect) = ui.allocate_space(egui::vec2(200.0, 20.0)); + ui.allocate_rect(rect, Sense::hover()); + ui.put(rect, |ui: &mut egui::Ui| { + ui.set_clip_rect(rect); + ui.add( + Username::new(profile.as_ref().ok(), note.pubkey()) + .abbreviated(15) + .pk_colored(true), + ) + }); + + ui.add(NoteContents::new(damus, &txn, &note, note_key)); + }); + + //render_note_actionbar(ui); + + //let header_res = ui.horizontal(|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()); + //collapse_state.toggle(ui); + //collapse_state.store(ui.ctx()); + //} + }); + + Ok(()) +} + fn render_note( ui: &mut egui::Ui, damus: &mut Damus, @@ -671,11 +702,10 @@ fn render_note( ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { ui.horizontal(|ui| { ui.spacing_mut().item_spacing.x = 2.0; - - render_username(ui, profile.as_ref().ok(), note.pubkey()); + ui.add(Username::new(profile.as_ref().ok(), note.pubkey()).abbreviated(20)); let note_cache = damus.get_note_cache_mut(note_key, note.created_at()); - render_reltime(ui, note_cache); + render_reltime(ui, note_cache, true); }); ui.add(NoteContents::new(damus, &txn, &note, note_key)); @@ -727,8 +757,14 @@ fn render_notes(ui: &mut egui::Ui, damus: &mut Damus, timeline: usize) { let num_notes = damus.timelines[timeline].notes.len(); + let renderer = if damus.irc_mode { + render_irc_note + } else { + render_note + }; + for i in 0..num_notes { - let _ = render_note(ui, damus, damus.timelines[timeline].notes[i].key, timeline); + let _ = renderer(ui, damus, damus.timelines[timeline].notes[i].key, timeline); ui.add(egui::Separator::default().spacing(0.0)); } @@ -778,6 +814,13 @@ fn render_panel<'a>(ctx: &egui::Context, app: &'a mut Damus, timeline_ind: usize ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| { ui.visuals_mut().button_frame = false; egui::widgets::global_dark_light_mode_switch(ui); + if ui + .add(egui::Button::new("A").frame(false)) + .on_hover_text("IRC mode") + .clicked() + { + app.irc_mode = !app.irc_mode; + } /* if ui diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs @@ -1 +1,2 @@ pub mod note; +pub mod username; diff --git a/src/widgets/username.rs b/src/widgets/username.rs @@ -0,0 +1,77 @@ +use crate::fonts::NamedFontFamily; +use egui::{Color32, Label, RichText, Widget}; +use nostrdb::ProfileRecord; + +pub struct Username<'a> { + profile: Option<&'a ProfileRecord<'a>>, + pk: &'a [u8; 32], + pk_colored: bool, + abbrev: usize, +} + +impl<'a> Username<'a> { + pub fn pk_colored(mut self, pk_colored: bool) -> Self { + self.pk_colored = pk_colored; + self + } + + pub fn abbreviated(mut self, amount: usize) -> Self { + self.abbrev = amount; + self + } + + pub fn new(profile: Option<&'a ProfileRecord>, pk: &'a [u8; 32]) -> Self { + let pk_colored = false; + let abbrev: usize = 1000; + Username { + profile, + pk, + pk_colored, + abbrev, + } + } +} + +impl<'a> Widget for Username<'a> { + fn ui(self, ui: &mut egui::Ui) -> egui::Response { + ui.horizontal(|ui| { + //ui.spacing_mut().item_spacing.x = 0.0; + if let Some(profile) = self.profile { + if let Some(prof) = profile.record.profile() { + let color = if self.pk_colored { + Some(pk_color(self.pk)) + } else { + None + }; + + if prof.display_name().is_some() && prof.display_name().unwrap() != "" { + ui_abbreviate_name(ui, prof.display_name().unwrap(), self.abbrev, color); + } else if let Some(name) = prof.name() { + ui_abbreviate_name(ui, name, self.abbrev, color); + } + } + } else { + ui.strong("nostrich"); + } + }) + .response + } +} + +fn ui_abbreviate_name(ui: &mut egui::Ui, name: &str, len: usize, color: Option<Color32>) { + if name.len() > len { + let closest = crate::abbrev::floor_char_boundary(name, len); + ui.strong(&name[..closest]); + ui.strong("..."); + } else { + let mut txt = RichText::new(name).family(NamedFontFamily::Medium.as_family()); + if let Some(c) = color { + txt = txt.color(c); + } + ui.add(Label::new(txt)); + } +} + +fn pk_color(pk: &[u8; 32]) -> Color32 { + Color32::from_rgb(pk[8], pk[10], pk[12]) +}