notedeck

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

commit 605f6f47115dc8736af04ffd6c8d7237fd0584bd
parent 4bdfbc640089347c4f61bf61ad7c364bd6066dd0
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 10 Jul 2025 15:45:33 -0700

android: hide new post button when navigating

Fixes: https://github.com/damus-io/notedeck/issues/898
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mcrates/notedeck_columns/src/app.rs | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mcrates/notedeck_columns/src/column.rs | 7++++++-
Mcrates/notedeck_columns/src/decks.rs | 30++++++++++++++++++++++++++----
Mcrates/notedeck_ui/src/contacts.rs | 6+-----
Mcrates/notedeck_ui/src/note/media.rs | 8++++----
5 files changed, 94 insertions(+), 26 deletions(-)

diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs @@ -8,7 +8,7 @@ use crate::{ storage, subscriptions::{SubKind, Subscriptions}, support::Support, - timeline::{self, thread::Threads, TimelineCache}, + timeline::{self, kind::ListKind, thread::Threads, TimelineCache, TimelineKind}, ui::{self, DesktopSidePanel}, view_state::ViewState, Result, @@ -581,25 +581,70 @@ fn render_damus_mobile( .is_some(); let darkmode = ui.ctx().style().visuals.dark_mode; - if ui - .put( + // only show the compose button on profile pages and on home + if should_show_compose_button(&app.decks_cache, app_ctx.accounts) { + let compose_resp = ui.put( rect, ui::post::compose_note_button(is_interactive, darkmode), - ) - .clicked() - && !app.columns(app_ctx.accounts).columns().is_empty() - { - let router = app.columns_mut(app_ctx.accounts).selected().router_mut(); - if router.top() == &Route::ComposeNote { - router.go_back(); - } else { - router.route_to(Route::ComposeNote); + ); + if compose_resp.clicked() && !app.columns(app_ctx.accounts).columns().is_empty() { + let router = app + .columns_mut(app_ctx.accounts) + .selected_mut() + .router_mut(); + if router.top() == &Route::ComposeNote { + router.go_back(); + } else { + router.route_to(Route::ComposeNote); + } } } app_action } +/// Should we show the compose button? When in threads we should hide it, etc +fn should_show_compose_button(decks: &DecksCache, accounts: &Accounts) -> bool { + let Some(col) = decks.selected_column(accounts) else { + return false; + }; + + match col.router().top() { + Route::Timeline(timeline_kind) => { + match timeline_kind { + TimelineKind::List(list_kind) => match list_kind { + ListKind::Contact(_pk) => true, + }, + + TimelineKind::Algo(_pk) => true, + TimelineKind::Profile(_pk) => true, + TimelineKind::Universe => true, + TimelineKind::Generic(_) => true, + TimelineKind::Hashtag(_) => true, + + // no! + TimelineKind::Search(_) => false, + TimelineKind::Notifications(_) => false, + } + } + + Route::Thread(_) => false, + Route::Accounts(_) => false, + Route::Reply(_) => false, + Route::Quote(_) => false, + Route::Relays => false, + Route::ComposeNote => false, + Route::AddColumn(_) => false, + Route::EditProfile(_) => false, + Route::Support => false, + Route::NewDeck => false, + Route::Search => false, + Route::EditDeck(_) => false, + Route::Wallet(_) => false, + Route::CustomizeZapAmount(_) => false, + } +} + #[profiling::function] fn render_damus_desktop( app: &mut Damus, diff --git a/crates/notedeck_columns/src/column.rs b/crates/notedeck_columns/src/column.rs @@ -158,7 +158,12 @@ impl Columns { } #[inline] - pub fn selected(&mut self) -> &mut Column { + pub fn selected(&self) -> &Column { + &self.columns[self.selected as usize] + } + + #[inline] + pub fn selected_mut(&mut self) -> &mut Column { &mut self.columns[self.selected as usize] } diff --git a/crates/notedeck_columns/src/decks.rs b/crates/notedeck_columns/src/decks.rs @@ -32,10 +32,15 @@ impl Default for DecksCache { impl DecksCache { /// Gets the first column in the currently active user's active deck pub fn selected_column_mut(&mut self, accounts: &notedeck::Accounts) -> Option<&mut Column> { - self.active_columns_mut(accounts).map(|ad| ad.selected()) + self.active_columns_mut(accounts) + .map(|ad| ad.selected_mut()) } - /// Gets the active columns + pub fn selected_column(&self, accounts: &notedeck::Accounts) -> Option<&Column> { + self.active_columns(accounts).map(|ad| ad.selected()) + } + + /// Gets a mutable reference to the active columns pub fn active_columns_mut(&mut self, accounts: &notedeck::Accounts) -> Option<&mut Columns> { let account = accounts.get_selected_account(); @@ -44,6 +49,15 @@ impl DecksCache { .map(|ad| ad.columns_mut()) } + /// Gets an immutable reference to the active columns + pub fn active_columns(&self, accounts: &notedeck::Accounts) -> Option<&Columns> { + let account = accounts.get_selected_account(); + + self.decks(&account.key.pubkey) + .active_deck() + .map(|ad| ad.columns()) + } + pub fn new(mut account_to_decks: HashMap<Pubkey, Decks>) -> Self { let fallback_pubkey = FALLBACK_PUBKEY(); account_to_decks.entry(fallback_pubkey).or_default(); @@ -187,7 +201,7 @@ impl Decks { &self.decks } - pub fn active_deck_mut(&mut self) -> Option<&mut Deck> { + fn active_deck_index(&self) -> Option<usize> { if self.decks.is_empty() { return None; } @@ -197,7 +211,15 @@ impl Decks { return None; } - Some(&mut self.decks[active]) + Some(active) + } + + pub fn active_deck(&self) -> Option<&Deck> { + self.active_deck_index().map(|ind| &self.decks[ind]) + } + + pub fn active_deck_mut(&mut self) -> Option<&mut Deck> { + self.active_deck_index().map(|ind| &mut self.decks[ind]) } pub fn decks_mut(&mut self) -> &mut Vec<Deck> { diff --git a/crates/notedeck_ui/src/contacts.rs b/crates/notedeck_ui/src/contacts.rs @@ -41,14 +41,10 @@ fn note_follows(contacts_note: Note<'_>, pk: &[u8; 32]) -> bool { continue; } - let Some(t) = tag.get_str(0) else { + let Some("p") = tag.get_str(0) else { continue; }; - if t != "p" { - continue; - } - let Some(author) = tag.get_id(1) else { continue; }; diff --git a/crates/notedeck_ui/src/note/media.rs b/crates/notedeck_ui/src/note/media.rs @@ -6,8 +6,8 @@ use egui::{ }; use notedeck::{ fonts::get_font_size, note::MediaAction, show_one_error_message, supported_mime_hosted_at_url, - ui::is_narrow, GifState, GifStateMap, Images, JobPool, MediaCache, MediaCacheType, - NotedeckTextStyle, TexturedImage, TexturesCache, UrlMimes, + GifState, GifStateMap, Images, JobPool, MediaCache, MediaCacheType, NotedeckTextStyle, + TexturedImage, TexturesCache, UrlMimes, }; use crate::{ @@ -30,8 +30,8 @@ pub(crate) fn image_carousel( ) -> Option<MediaAction> { // let's make sure everything is within our area - let height = if is_narrow(ui.ctx()) { 90.0 } else { 360.0 }; - + //let height = if is_narrow(ui.ctx()) { 90.0 } else { 360.0 }; + let height = 360.0; let width = ui.available_width(); let show_popup = get_show_popup(ui, popup_id(carousel_id));