notedeck

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

commit 391abe817d1ab6b73375346387cad70a9edfbf73
parent 30eb2e0258c06b1c673ca0e028403e795653e355
Author: William Casarin <jb55@jb55.com>
Date:   Sun,  3 Aug 2025 14:02:05 -0700

columns: clean up flags, refactor content rendering

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

Diffstat:
Mcrates/notedeck_columns/src/app.rs | 4++--
Mcrates/notedeck_columns/src/ui/settings.rs | 16++++++++--------
Mcrates/notedeck_columns/src/ui/thread.rs | 2+-
Mcrates/notedeck_ui/src/note/contents.rs | 102+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mcrates/notedeck_ui/src/note/mod.rs | 8+++-----
Mcrates/notedeck_ui/src/note/options.rs | 8++++----
6 files changed, 81 insertions(+), 59 deletions(-)

diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs @@ -592,12 +592,12 @@ fn get_note_options(args: ColumnsArgs, settings_handler: &mut SettingsHandler) - args.is_flag_set(ColumnsFlag::NoMedia), ); note_options.set( - NoteOptions::ShowNoteClientTop, + NoteOptions::ClientNameTop, ShowSourceClientOption::Top == settings_handler.show_source_client().into() || args.is_flag_set(ColumnsFlag::ShowNoteClientTop), ); note_options.set( - NoteOptions::ShowNoteClientBottom, + NoteOptions::ClientNameBottom, ShowSourceClientOption::Bottom == settings_handler.show_source_client().into() || args.is_flag_set(ColumnsFlag::ShowNoteClientBottom), ); diff --git a/crates/notedeck_columns/src/ui/settings.rs b/crates/notedeck_columns/src/ui/settings.rs @@ -43,9 +43,9 @@ impl From<ShowSourceClientOption> for String { impl From<NoteOptions> for ShowSourceClientOption { fn from(note_options: NoteOptions) -> Self { - if note_options.contains(NoteOptions::ShowNoteClientTop) { + if note_options.contains(NoteOptions::ClientNameTop) { ShowSourceClientOption::Top - } else if note_options.contains(NoteOptions::ShowNoteClientBottom) { + } else if note_options.contains(NoteOptions::ClientNameBottom) { ShowSourceClientOption::Bottom } else { ShowSourceClientOption::Hide @@ -68,16 +68,16 @@ impl ShowSourceClientOption { pub fn set_note_options(self, note_options: &mut NoteOptions) { match self { Self::Hide => { - note_options.set(NoteOptions::ShowNoteClientTop, false); - note_options.set(NoteOptions::ShowNoteClientBottom, false); + note_options.set(NoteOptions::ClientNameTop, false); + note_options.set(NoteOptions::ClientNameBottom, false); } Self::Bottom => { - note_options.set(NoteOptions::ShowNoteClientTop, false); - note_options.set(NoteOptions::ShowNoteClientBottom, true); + note_options.set(NoteOptions::ClientNameTop, false); + note_options.set(NoteOptions::ClientNameBottom, true); } Self::Top => { - note_options.set(NoteOptions::ShowNoteClientTop, true); - note_options.set(NoteOptions::ShowNoteClientBottom, false); + note_options.set(NoteOptions::ClientNameTop, true); + note_options.set(NoteOptions::ClientNameBottom, false); } } } diff --git a/crates/notedeck_columns/src/ui/thread.rs b/crates/notedeck_columns/src/ui/thread.rs @@ -292,12 +292,12 @@ struct ThreadNote<'a> { impl<'a> ThreadNote<'a> { fn options(&self, mut cur_options: NoteOptions) -> NoteOptions { - cur_options.set(NoteOptions::ShowCreatedAtBottom, true); match self.note_type { ThreadNoteType::Chain { root: _ } => cur_options, ThreadNoteType::Selected { root: _ } => { cur_options.set(NoteOptions::Wide, true); cur_options.set(NoteOptions::SelectableText, true); + cur_options.set(NoteOptions::FullCreatedDate, true); cur_options } ThreadNoteType::Reply => cur_options, diff --git a/crates/notedeck_ui/src/note/contents.rs b/crates/notedeck_ui/src/note/contents.rs @@ -5,6 +5,7 @@ use crate::{ }; use egui::{Color32, Hyperlink, Label, RichText}; use nostrdb::{BlockType, Mention, Note, NoteKey, Transaction}; +use notedeck::Localization; use notedeck::{ time_format, update_imeta_blurhashes, IsFollowing, NoteCache, NoteContext, NotedeckTextStyle, }; @@ -42,14 +43,6 @@ impl<'a, 'd> NoteContents<'a, 'd> { impl egui::Widget for &mut NoteContents<'_, '_> { fn ui(self, ui: &mut egui::Ui) -> egui::Response { - let create_at_bottom = self.options.contains(NoteOptions::ShowCreatedAtBottom); - if self.options.contains(NoteOptions::ShowNoteClientTop) { - render_client(ui, self.note_context.note_cache, self.note, false); - } - // bottom created at only on selected note - if create_at_bottom { - self.options.set(NoteOptions::ShowCreatedAtBottom, false); - } let result = render_note_contents( ui, self.note_context, @@ -58,44 +51,27 @@ impl egui::Widget for &mut NoteContents<'_, '_> { self.options, self.jobs, ); - ui.horizontal(|ui| { - if create_at_bottom { - secondary_label( - ui, - time_format(self.note_context.i18n, self.note.created_at()), - ); - } - - if self.options.contains(NoteOptions::ShowNoteClientBottom) { - render_client( - ui, - self.note_context.note_cache, - self.note, - create_at_bottom, - ); - } - }); - self.action = result.action; result.response } } -#[profiling::function] -fn render_client(ui: &mut egui::Ui, note_cache: &mut NoteCache, note: &Note, before: bool) { +fn render_client_name(ui: &mut egui::Ui, note_cache: &mut NoteCache, note: &Note, before: bool) { let cached_note = note_cache.cached_note_or_insert_mut(note.key().unwrap(), note); - match cached_note.client.as_deref() { - Some(client) if !client.is_empty() => { - ui.horizontal(|ui| { - if before { - secondary_label(ui, "⋅"); - } - secondary_label(ui, format!("via {client}")); - }); - } - _ => return, + let Some(client) = cached_note.client.as_ref() else { + return; + }; + + if client.is_empty() { + return; + } + + if before { + secondary_label(ui, "⋅"); } + + secondary_label(ui, format!("via {client}")); } /// Render an inline note preview with a border. These are used when @@ -144,9 +120,57 @@ pub fn render_note_preview( .show(ui) } +/// Render note contents and surrounding info (client name, full date timestamp) +fn render_note_contents( + ui: &mut egui::Ui, + note_context: &mut NoteContext, + txn: &Transaction, + note: &Note, + options: NoteOptions, + jobs: &mut JobsCache, +) -> NoteResponse { + if options.contains(NoteOptions::ClientNameTop) { + let before_date = false; + render_client_name(ui, note_context.note_cache, note, before_date); + } + + let response = render_undecorated_note_contents(ui, note_context, txn, note, options, jobs); + + ui.horizontal_wrapped(|ui| { + note_bottom_metadata_ui( + ui, + note_context.i18n, + note_context.note_cache, + note, + options, + ); + }); + + response +} + +/// Client name, full timestamp, etc +fn note_bottom_metadata_ui( + ui: &mut egui::Ui, + i18n: &mut Localization, + note_cache: &mut NoteCache, + note: &Note, + options: NoteOptions, +) { + let show_full_date = options.contains(NoteOptions::FullCreatedDate); + + if show_full_date { + secondary_label(ui, time_format(i18n, note.created_at())); + } + + if options.contains(NoteOptions::ClientNameBottom) { + render_client_name(ui, note_cache, note, show_full_date); + } +} + #[allow(clippy::too_many_arguments)] #[profiling::function] -pub fn render_note_contents<'a>( +fn render_undecorated_note_contents<'a>( ui: &mut egui::Ui, note_context: &mut NoteContext, txn: &Transaction, diff --git a/crates/notedeck_ui/src/note/mod.rs b/crates/notedeck_ui/src/note/mod.rs @@ -10,7 +10,7 @@ use crate::{ PulseAlpha, Username, }; -pub use contents::{render_note_contents, render_note_preview, NoteContents}; +pub use contents::{render_note_preview, NoteContents}; pub use context::NoteContextButton; use notedeck::get_current_wallet; use notedeck::note::ZapTargetAmount; @@ -366,11 +366,11 @@ impl<'a, 'd> NoteView<'a, 'd> { flags: NoteOptions, ) { let horiz_resp = ui - .horizontal(|ui| { + .horizontal_wrapped(|ui| { ui.spacing_mut().item_spacing.x = if is_narrow(ui.ctx()) { 1.0 } else { 2.0 }; let response = ui .add(Username::new(i18n, profile.as_ref().ok(), note.pubkey()).abbreviated(20)); - if !flags.contains(NoteOptions::ShowCreatedAtBottom) { + if !flags.contains(NoteOptions::FullCreatedDate) { return render_notetime(ui, i18n, note.created_at(), true).response; } response @@ -508,8 +508,6 @@ impl<'a, 'd> NoteView<'a, 'd> { let pfp_rect = pfp_resp.bounding_rect; let mut note_action: Option<NoteAction> = pfp_resp.into_action(self.note.pubkey()); - self.flags.set(NoteOptions::ShowCreatedAtBottom, false); - ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { NoteView::note_header( ui, diff --git a/crates/notedeck_ui/src/note/options.rs b/crates/notedeck_ui/src/note/options.rs @@ -23,13 +23,13 @@ bitflags! { /// will end with a ... and a "Show more" button. const Truncate = 1 << 11; /// Show note's client in the note content - const ShowNoteClientTop = 1 << 12; - const ShowNoteClientBottom = 1 << 13; + const ClientNameTop = 1 << 12; + const ClientNameBottom = 1 << 13; const RepliesNewestFirst = 1 << 14; - // Show note's created at note bottom - const ShowCreatedAtBottom = 1 << 15; + /// Show note's full created at date at the bottom + const FullCreatedDate = 1 << 15; } }