diff --git a/crates/notedeck_columns/src/route.rs b/crates/notedeck_columns/src/route.rs index 159426cd..274a0aba 100644 --- a/crates/notedeck_columns/src/route.rs +++ b/crates/notedeck_columns/src/route.rs @@ -1,13 +1,10 @@ use enostr::{NoteId, Pubkey}; -use std::{ - borrow::Cow, - fmt::{self}, -}; +use std::fmt::{self}; use crate::{ accounts::AccountsRoute, column::Columns, - timeline::{TimelineId, TimelineRoute}, + timeline::{kind::ColumnTitle, TimelineId, TimelineRoute}, ui::add_column::AddColumnRoute, }; @@ -65,7 +62,7 @@ impl Route { Route::Accounts(AccountsRoute::AddAccount) } - pub fn title(&self, columns: &Columns) -> Cow<'static, str> { + pub fn title<'a>(&self, columns: &'a Columns) -> ColumnTitle<'a> { match self { Route::Timeline(tlr) => match tlr { TimelineRoute::Timeline(id) => { @@ -74,36 +71,38 @@ impl Route { .expect("expected to find timeline"); timeline.kind.to_title() } - TimelineRoute::Thread(_id) => Cow::Borrowed("Thread"), - TimelineRoute::Reply(_id) => Cow::Borrowed("Reply"), - TimelineRoute::Quote(_id) => Cow::Borrowed("Quote"), - TimelineRoute::Profile(_pubkey) => Cow::Borrowed("Profile"), + TimelineRoute::Thread(_id) => ColumnTitle::simple("Thread"), + TimelineRoute::Reply(_id) => ColumnTitle::simple("Reply"), + TimelineRoute::Quote(_id) => ColumnTitle::simple("Quote"), + TimelineRoute::Profile(_pubkey) => ColumnTitle::simple("Profile"), }, - Route::Relays => Cow::Borrowed("Relays"), + Route::Relays => ColumnTitle::simple("Relays"), Route::Accounts(amr) => match amr { - AccountsRoute::Accounts => Cow::Borrowed("Accounts"), - AccountsRoute::AddAccount => Cow::Borrowed("Add Account"), + AccountsRoute::Accounts => ColumnTitle::simple("Accounts"), + AccountsRoute::AddAccount => ColumnTitle::simple("Add Account"), }, - Route::ComposeNote => Cow::Borrowed("Compose Note"), + Route::ComposeNote => ColumnTitle::simple("Compose Note"), Route::AddColumn(c) => match c { - AddColumnRoute::Base => Cow::Borrowed("Add Column"), - AddColumnRoute::UndecidedNotification => Cow::Borrowed("Add Notifications Column"), - AddColumnRoute::ExternalNotification => { - Cow::Borrowed("Add External Notifications Column") + AddColumnRoute::Base => ColumnTitle::simple("Add Column"), + AddColumnRoute::UndecidedNotification => { + ColumnTitle::simple("Add Notifications Column") } - AddColumnRoute::Hashtag => Cow::Borrowed("Add Hashtag Column"), + AddColumnRoute::ExternalNotification => { + ColumnTitle::simple("Add External Notifications Column") + } + AddColumnRoute::Hashtag => ColumnTitle::simple("Add Hashtag Column"), AddColumnRoute::UndecidedIndividual => { - Cow::Borrowed("Subscribe to someone's notes") + ColumnTitle::simple("Subscribe to someone's notes") } AddColumnRoute::ExternalIndividual => { - Cow::Borrowed("Subscribe to someone else's notes") + ColumnTitle::simple("Subscribe to someone else's notes") } }, - Route::Support => Cow::Borrowed("Damus Support"), - Route::NewDeck => Cow::Borrowed("Add Deck"), - Route::EditDeck(_) => Cow::Borrowed("Edit Deck"), + Route::Support => ColumnTitle::simple("Damus Support"), + Route::NewDeck => ColumnTitle::simple("Add Deck"), + Route::EditDeck(_) => ColumnTitle::simple("Edit Deck"), } } } diff --git a/crates/notedeck_columns/src/timeline/kind.rs b/crates/notedeck_columns/src/timeline/kind.rs index 49178d3f..30acec4c 100644 --- a/crates/notedeck_columns/src/timeline/kind.rs +++ b/crates/notedeck_columns/src/timeline/kind.rs @@ -194,16 +194,75 @@ impl TimelineKind { } } - pub fn to_title(&self) -> Cow<'static, str> { + pub fn to_title(&self) -> ColumnTitle<'_> { match self { TimelineKind::List(list_kind) => match list_kind { - ListKind::Contact(_pubkey_source) => Cow::Borrowed("Contacts"), + ListKind::Contact(_pubkey_source) => ColumnTitle::simple("Contacts"), }, - TimelineKind::Notifications(_pubkey_source) => Cow::Borrowed("Notifications"), - TimelineKind::Profile(_pubkey_source) => Cow::Borrowed("Notes"), - TimelineKind::Universe => Cow::Borrowed("Universe"), - TimelineKind::Generic => Cow::Borrowed("Custom"), - TimelineKind::Hashtag(hashtag) => Cow::Owned(format!("#{}", hashtag)), + TimelineKind::Notifications(_pubkey_source) => ColumnTitle::simple("Notifications"), + TimelineKind::Profile(_pubkey_source) => ColumnTitle::needs_db(self), + TimelineKind::Universe => ColumnTitle::simple("Universe"), + TimelineKind::Generic => ColumnTitle::simple("Custom"), + TimelineKind::Hashtag(hashtag) => ColumnTitle::formatted(format!("#{}", hashtag)), } } } + +#[derive(Debug)] +pub struct TitleNeedsDb<'a> { + kind: &'a TimelineKind, +} + +impl<'a> TitleNeedsDb<'a> { + pub fn new(kind: &'a TimelineKind) -> Self { + TitleNeedsDb { kind } + } + + pub fn title<'txn>( + &self, + txn: &'txn Transaction, + ndb: &Ndb, + deck_author: Option<&Pubkey>, + ) -> &'txn str { + if let TimelineKind::Profile(pubkey_source) = self.kind { + if let Some(deck_author) = deck_author { + let pubkey = pubkey_source.to_pubkey(deck_author); + let profile = ndb.get_profile_by_pubkey(txn, pubkey); + let m_name = profile + .ok() + .as_ref() + .and_then(|p| crate::profile::get_profile_name(p)) + .map(|display_name| display_name.username()); + + m_name.unwrap_or("Profile") + } else { + // why would be there be no deck author? weird + "nostrich" + } + } else { + "Unknown" + } + } +} + +/// This saves us from having to construct a transaction if we don't need to +/// for a particular column when rendering the title +#[derive(Debug)] +pub enum ColumnTitle<'a> { + Simple(Cow<'static, str>), + NeedsDb(TitleNeedsDb<'a>), +} + +impl<'a> ColumnTitle<'a> { + pub fn simple(title: &'static str) -> Self { + Self::Simple(Cow::Borrowed(title)) + } + + pub fn formatted(title: String) -> Self { + Self::Simple(Cow::Owned(title)) + } + + pub fn needs_db(kind: &'a TimelineKind) -> ColumnTitle<'a> { + Self::NeedsDb(TitleNeedsDb::new(kind)) + } +} diff --git a/crates/notedeck_columns/src/timeline/mod.rs b/crates/notedeck_columns/src/timeline/mod.rs index 23c27aea..e60d02c9 100644 --- a/crates/notedeck_columns/src/timeline/mod.rs +++ b/crates/notedeck_columns/src/timeline/mod.rs @@ -26,7 +26,7 @@ use tracing::{debug, error, info, warn}; pub mod kind; pub mod route; -pub use kind::{PubkeySource, TimelineKind}; +pub use kind::{ColumnTitle, PubkeySource, TimelineKind}; pub use route::TimelineRoute; #[derive(Debug, Hash, Copy, Clone, Eq, PartialEq)] diff --git a/crates/notedeck_columns/src/ui/column/header.rs b/crates/notedeck_columns/src/ui/column/header.rs index 9ca66c98..f05987e5 100644 --- a/crates/notedeck_columns/src/ui/column/header.rs +++ b/crates/notedeck_columns/src/ui/column/header.rs @@ -2,7 +2,7 @@ use crate::{ column::Columns, nav::RenderNavAction, route::Route, - timeline::{TimelineId, TimelineRoute}, + timeline::{ColumnTitle, TimelineId, TimelineRoute}, ui::{ self, anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE}, @@ -105,17 +105,29 @@ impl<'a> NavTitle<'a> { // not it looks cool self.title_pfp(ui, prev, 32.0); - let back_label = ui.add( - egui::Label::new( - RichText::new(prev.title(self.columns).to_string()) - .color(color) - .text_style(NotedeckTextStyle::Body.text_style()), - ) - .selectable(false) - .sense(egui::Sense::click()), - ); + let column_title = prev.title(self.columns); - back_label.union(chev_resp) + let back_resp = match &column_title { + ColumnTitle::Simple(title) => ui.add(Self::back_label(title, color)), + + ColumnTitle::NeedsDb(need_db) => { + let txn = Transaction::new(self.ndb).unwrap(); + let title = need_db.title(&txn, self.ndb, self.deck_author); + ui.add(Self::back_label(title, color)) + } + }; + + back_resp.union(chev_resp) + } + + fn back_label(title: &str, color: egui::Color32) -> egui::Label { + egui::Label::new( + RichText::new(title.to_string()) + .color(color) + .text_style(NotedeckTextStyle::Body.text_style()), + ) + .selectable(false) + .sense(egui::Sense::click()) } fn delete_column_button(&self, ui: &mut egui::Ui, icon_width: f32) -> egui::Response { @@ -209,14 +221,25 @@ impl<'a> NavTitle<'a> { } } + fn title_label_value(title: &str) -> egui::Label { + egui::Label::new(RichText::new(title).text_style(NotedeckTextStyle::Body.text_style())) + .selectable(false) + } + fn title_label(&self, ui: &mut egui::Ui, top: &Route) { - ui.add( - egui::Label::new( - RichText::new(top.title(self.columns)) - .text_style(NotedeckTextStyle::Body.text_style()), - ) - .selectable(false), - ); + let column_title = top.title(self.columns); + + match &column_title { + ColumnTitle::Simple(title) => { + ui.add(Self::title_label_value(title)); + } + + ColumnTitle::NeedsDb(need_db) => { + let txn = Transaction::new(self.ndb).unwrap(); + let title = need_db.title(&txn, self.ndb, self.deck_author); + ui.add(Self::title_label_value(title)); + } + }; } fn title(