notedeck

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

commit 26d027f03e413a3374dfff908a145cf0de9b3fc1
parent 605f6f47115dc8736af04ffd6c8d7237fd0584bd
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 10 Jul 2025 16:16:10 -0700

nav: nav to accounts view for actions that require key

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

Diffstat:
Mcrates/notedeck_columns/src/actionbar.rs | 18+++++++++++++++---
Mcrates/notedeck_columns/src/app.rs | 31+++++++++++--------------------
Mcrates/notedeck_columns/src/ui/post.rs | 17+++++------------
Mcrates/notedeck_columns/src/ui/side_panel.rs | 20+++++++++-----------
Mcrates/notedeck_ui/src/anim.rs | 4++--
5 files changed, 42 insertions(+), 48 deletions(-)

diff --git a/crates/notedeck_columns/src/actionbar.rs b/crates/notedeck_columns/src/actionbar.rs @@ -57,6 +57,7 @@ fn execute_note_action( ) -> NoteActionResponse { let mut timeline_res = None; let mut router_action = None; + let can_post = accounts.get_selected_account().key.secret_key.is_some(); match action { NoteAction::Scroll(ref scroll_info) => { @@ -64,7 +65,11 @@ fn execute_note_action( } NoteAction::Reply(note_id) => { - router_action = Some(RouterAction::route_to(Route::reply(note_id))); + if can_post { + router_action = Some(RouterAction::route_to(Route::reply(note_id))); + } else { + router_action = Some(RouterAction::route_to(Route::accounts())); + } } NoteAction::Profile(pubkey) => { let kind = TimelineKind::Profile(pubkey); @@ -99,7 +104,11 @@ fn execute_note_action( .map(NotesOpenResult::Timeline); } NoteAction::Quote(note_id) => { - router_action = Some(RouterAction::route_to(Route::quote(note_id))); + if can_post { + router_action = Some(RouterAction::route_to(Route::quote(note_id))); + } else { + router_action = Some(RouterAction::route_to(Route::accounts())); + } } NoteAction::Zap(zap_action) => { let cur_acc = accounts.get_selected_account(); @@ -336,7 +345,10 @@ pub fn process_thread_notes( let note = if let Ok(note) = ndb.get_note_by_key(txn, *key) { note } else { - tracing::error!("hit race condition in poll_notes_into_view: https://github.com/damus-io/nostrdb/issues/35 note {:?} was not added to timeline", key); + tracing::error!( + "hit race condition in poll_notes_into_view: https://github.com/damus-io/nostrdb/issues/35 note {:?} was not added to timeline", + key + ); continue; }; diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs @@ -9,7 +9,7 @@ use crate::{ subscriptions::{SubKind, Subscriptions}, support::Support, timeline::{self, kind::ListKind, thread::Threads, TimelineCache, TimelineKind}, - ui::{self, DesktopSidePanel}, + ui::{self, DesktopSidePanel, SidePanelAction}, view_state::ViewState, Result, }; @@ -573,30 +573,21 @@ fn render_damus_mobile( rect.min.x = rect.max.x - if is_narrow(ui.ctx()) { 60.0 } else { 100.0 }; rect.min.y = rect.max.y - 100.0; - let is_interactive = app_ctx - .accounts - .get_selected_account() - .key - .secret_key - .is_some(); let darkmode = ui.ctx().style().visuals.dark_mode; // 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), - ); + let compose_resp = ui.put(rect, ui::post::compose_note_button(darkmode)); + if compose_resp.hovered() { + notedeck_ui::show_pointer(ui); + } 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); - } + // just use the some side panel logic as the desktop + DesktopSidePanel::perform_action( + &mut app.decks_cache, + app_ctx.accounts, + SidePanelAction::ComposeNote, + ); } } diff --git a/crates/notedeck_columns/src/ui/post.rs b/crates/notedeck_columns/src/ui/post.rs @@ -4,7 +4,7 @@ use notedeck_ui::anim::AnimationHelper; static ICON_WIDTH: f32 = 40.0; static ICON_EXPANSION_MULTIPLE: f32 = 1.2; -pub fn compose_note_button(interactive: bool, dark_mode: bool) -> impl Widget { +pub fn compose_note_button(dark_mode: bool) -> impl Widget { move |ui: &mut egui::Ui| -> egui::Response { let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget @@ -12,11 +12,7 @@ pub fn compose_note_button(interactive: bool, dark_mode: bool) -> impl Widget { let min_plus_sign_size = 14.0; // length of the plus sign let min_line_width = 2.25; // width of the plus sign - let helper = if interactive { - AnimationHelper::new(ui, "note-compose-button", vec2(max_size, max_size)) - } else { - AnimationHelper::no_animation(ui, vec2(max_size, max_size)) - }; + let helper = AnimationHelper::new(ui, "note-compose-button", vec2(max_size, max_size)); let painter = ui.painter_at(helper.get_animation_rect()); @@ -24,11 +20,8 @@ pub fn compose_note_button(interactive: bool, dark_mode: bool) -> impl Widget { let use_line_width = helper.scale_1d_pos(min_line_width); let use_edge_circle_radius = helper.scale_radius(min_line_width); - let fill_color = if interactive { - notedeck_ui::colors::PINK - } else { - ui.visuals().noninteractive().bg_fill - }; + // TODO: theme!? + let fill_color = notedeck_ui::colors::PINK; painter.circle_filled(helper.center(), use_background_radius, fill_color); @@ -38,7 +31,7 @@ pub fn compose_note_button(interactive: bool, dark_mode: bool) -> impl Widget { let west_edge = helper.scale_from_center(-min_half_plus_sign_size, 0.0); let east_edge = helper.scale_from_center(min_half_plus_sign_size, 0.0); - let icon_color = if !dark_mode && !interactive { + let icon_color = if !dark_mode { Color32::BLACK } else { Color32::WHITE diff --git a/crates/notedeck_columns/src/ui/side_panel.rs b/crates/notedeck_columns/src/ui/side_panel.rs @@ -92,16 +92,7 @@ impl<'a> DesktopSidePanel<'a> { // ui.add_space(24.0); //} - let is_interactive = self.selected_account.key.secret_key.is_some(); - let compose_resp = ui.add(crate::ui::post::compose_note_button( - is_interactive, - dark_mode, - )); - let compose_resp = if is_interactive { - compose_resp - } else { - compose_resp.on_hover_cursor(egui::CursorIcon::NotAllowed) - }; + let compose_resp = ui.add(crate::ui::post::compose_note_button(dark_mode)); let search_resp = ui.add(search_button()); let column_resp = ui.add(add_column_button()); @@ -135,6 +126,9 @@ impl<'a> DesktopSidePanel<'a> { SidePanelAction::ComposeNote, compose_resp, )) + } else if compose_resp.hovered() { + notedeck_ui::show_pointer(ui); + None } else if search_resp.clicked() { Some(InnerResponse::new(SidePanelAction::Search, search_resp)) } else if column_resp.clicked() { @@ -226,7 +220,11 @@ impl<'a> DesktopSidePanel<'a> { } } SidePanelAction::ComposeNote => { - if router.routes().iter().any(|r| r == &Route::ComposeNote) { + let can_post = accounts.get_selected_account().key.secret_key.is_some(); + + if !can_post { + router.route_to(Route::accounts()); + } else if router.routes().iter().any(|r| r == &Route::ComposeNote) { router.go_back(); } else { router.route_to(Route::ComposeNote); diff --git a/crates/notedeck_ui/src/anim.rs b/crates/notedeck_ui/src/anim.rs @@ -60,8 +60,8 @@ impl AnimationHelper { } } - pub fn no_animation(ui: &mut egui::Ui, size: egui::Vec2) -> Self { - let (rect, response) = ui.allocate_exact_size(size, Sense::hover()); + pub fn no_animation(ui: &mut egui::Ui, size: egui::Vec2, sense: Sense) -> Self { + let (rect, response) = ui.allocate_exact_size(size, sense); Self { rect,