notedeck

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

commit 3540290f0ab6e78c2af0b66ad9210beef7969a36
parent 2533448180d0a501e03aac3547051ee5d2dc4021
Author: kernelkind <kernelkind@gmail.com>
Date:   Mon, 22 Sep 2025 15:15:40 -0400

make update return AppResponse instead of Option<AppAction>

Signed-off-by: kernelkind <kernelkind@gmail.com>

Diffstat:
Mcrates/notedeck/src/app.rs | 26+++++++++++++++++++++++++-
Mcrates/notedeck/src/lib.rs | 2+-
Mcrates/notedeck_chrome/src/app.rs | 4++--
Mcrates/notedeck_chrome/src/chrome.rs | 8+++++---
Mcrates/notedeck_clndash/src/lib.rs | 7++++---
Mcrates/notedeck_columns/src/app.rs | 42+++++++++++++++++++++++-------------------
Mcrates/notedeck_columns/src/nav.rs | 7+++++++
Mcrates/notedeck_columns/src/ui/account_login_view.rs | 8++++----
Mcrates/notedeck_columns/src/ui/configure_deck.rs | 6+++---
Mcrates/notedeck_columns/src/ui/edit_deck.rs | 6+++---
Mcrates/notedeck_columns/src/ui/note/post.rs | 6+++---
Mcrates/notedeck_columns/src/ui/preview.rs | 10+++-------
Mcrates/notedeck_columns/src/ui/relay.rs | 6+++---
Mcrates/notedeck_dave/src/lib.rs | 6+++---
Mcrates/notedeck_notebook/src/lib.rs | 6+++---
15 files changed, 92 insertions(+), 58 deletions(-)

diff --git a/crates/notedeck/src/app.rs b/crates/notedeck/src/app.rs @@ -31,7 +31,31 @@ pub enum AppAction { } pub trait App { - fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction>; + fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse; +} + +#[derive(Default)] +pub struct AppResponse { + pub action: Option<AppAction>, + pub can_take_drag_from: Vec<egui::Id>, +} + +impl AppResponse { + pub fn none() -> Self { + Self::default() + } + + pub fn action(action: Option<AppAction>) -> Self { + Self { + action, + can_take_drag_from: Vec::new(), + } + } + + pub fn drag(mut self, can_take_drag_from: Vec<egui::Id>) -> Self { + self.can_take_drag_from.extend(can_take_drag_from); + self + } } /// Main notedeck app framework diff --git a/crates/notedeck/src/lib.rs b/crates/notedeck/src/lib.rs @@ -44,7 +44,7 @@ pub use account::accounts::{AccountData, AccountSubs, Accounts}; pub use account::contacts::{ContactState, IsFollowing}; pub use account::relay::RelayAction; pub use account::FALLBACK_PUBKEY; -pub use app::{App, AppAction, Notedeck}; +pub use app::{App, AppAction, AppResponse, Notedeck}; pub use args::Args; pub use context::{AppContext, SoftKeyboardContext}; pub use error::{show_one_error_message, Error, FilterError, ZapError}; diff --git a/crates/notedeck_chrome/src/app.rs b/crates/notedeck_chrome/src/app.rs @@ -1,4 +1,4 @@ -use notedeck::{AppAction, AppContext}; +use notedeck::{AppContext, AppResponse}; use notedeck_clndash::ClnDash; use notedeck_columns::Damus; use notedeck_dave::Dave; @@ -14,7 +14,7 @@ pub enum NotedeckApp { } impl notedeck::App for NotedeckApp { - fn update(&mut self, ctx: &mut AppContext, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, ctx: &mut AppContext, ui: &mut egui::Ui) -> AppResponse { match self { NotedeckApp::Dave(dave) => dave.update(ctx, ui), NotedeckApp::Columns(columns) => columns.update(ctx, ui), diff --git a/crates/notedeck_chrome/src/chrome.rs b/crates/notedeck_chrome/src/chrome.rs @@ -8,6 +8,7 @@ use eframe::CreationContext; use egui::{vec2, Button, Color32, Label, Layout, Rect, RichText, ThemePreference, Widget}; use egui_extras::{Size, StripBuilder}; use nostrdb::{ProfileRecord, Transaction}; +use notedeck::AppResponse; use notedeck::Error; use notedeck::SoftKeyboardContext; use notedeck::{ @@ -255,7 +256,8 @@ impl Chrome { ); */ - if let Some(action) = self.apps[self.active as usize].update(app_ctx, ui) { + let resp = self.apps[self.active as usize].update(app_ctx, ui); + if let Some(action) = resp.action { chrome_handle_app_action(self, app_ctx, action, ui); } }); @@ -378,12 +380,12 @@ impl Chrome { } impl notedeck::App for Chrome { - fn update(&mut self, ctx: &mut notedeck::AppContext, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, ctx: &mut notedeck::AppContext, ui: &mut egui::Ui) -> AppResponse { if let Some(action) = self.show(ctx, ui) { action.process(ctx, self, ui); } // TODO: unify this constant with the columns side panel width. ui crate? - None + AppResponse::none() } } diff --git a/crates/notedeck_clndash/src/lib.rs b/crates/notedeck_clndash/src/lib.rs @@ -13,7 +13,8 @@ use crate::watch::fetch_paid_invoices; use lnsocket::bitcoin::secp256k1::{PublicKey, SecretKey, rand}; use lnsocket::{CommandoClient, LNSocket}; use nostrdb::Ndb; -use notedeck::{AppAction, AppContext}; +use notedeck::AppContext; +use notedeck::AppResponse; use serde_json::json; use std::collections::HashMap; use std::str::FromStr; @@ -59,7 +60,7 @@ struct CommChannel { } impl notedeck::App for ClnDash { - fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { if !self.initialized { self.connection_state = ConnectionState::Connecting; @@ -71,7 +72,7 @@ impl notedeck::App for ClnDash { self.show(ui, ctx); - None + AppResponse::none() } } diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs @@ -20,8 +20,8 @@ use egui_extras::{Size, StripBuilder}; use enostr::{ClientMessage, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool}; use nostrdb::Transaction; use notedeck::{ - tr, ui::is_narrow, Accounts, AppAction, AppContext, DataPath, DataPathType, FilterState, - Images, JobsCache, Localization, NotedeckOptions, SettingsHandler, UnknownIds, + tr, ui::is_narrow, Accounts, AppAction, AppContext, AppResponse, DataPath, DataPathType, + FilterState, Images, JobsCache, Localization, NotedeckOptions, SettingsHandler, UnknownIds, }; use notedeck_ui::{ media::{MediaViewer, MediaViewerFlags, MediaViewerState}, @@ -375,16 +375,12 @@ fn process_message(damus: &mut Damus, ctx: &mut AppContext<'_>, relay: &str, msg } } -fn render_damus( - damus: &mut Damus, - app_ctx: &mut AppContext<'_>, - ui: &mut egui::Ui, -) -> Option<AppAction> { +fn render_damus(damus: &mut Damus, app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { damus .note_options .set(NoteOptions::Wide, is_narrow(ui.ctx())); - let app_action = if notedeck::ui::is_narrow(ui.ctx()) { + let app_resp = if notedeck::ui::is_narrow(ui.ctx()) { render_damus_mobile(damus, app_ctx, ui) } else { render_damus_desktop(damus, app_ctx, ui) @@ -395,7 +391,7 @@ fn render_damus( // We use this for keeping timestamps and things up to date //ui.ctx().request_repaint_after(Duration::from_secs(5)); - app_action + app_resp } /// Present a fullscreen media viewer if the FullscreenMedia AppOptions flag is set. This is @@ -641,9 +637,10 @@ fn render_damus_mobile( app: &mut Damus, app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui, -) -> Option<AppAction> { +) -> AppResponse { //let routes = app.timelines[0].routes.clone(); + let mut can_take_drag_from = Vec::new(); let active_col = app.columns_mut(app_ctx.i18n, app_ctx.accounts).selected as usize; let mut app_action: Option<AppAction> = None; // don't show toolbar if soft keyboard is open @@ -664,14 +661,17 @@ fn render_damus_mobile( strip.cell(|ui| { let rect = ui.available_rect_before_wrap(); if !app.columns(app_ctx.accounts).columns().is_empty() { - let r = nav::render_nav( + let resp = nav::render_nav( active_col, ui.available_rect_before_wrap(), app, app_ctx, ui, - ) - .process_render_nav_response(app, app_ctx, ui); + ); + + can_take_drag_from.extend(resp.can_take_drag_from()); + + let r = resp.process_render_nav_response(app, app_ctx, ui); if let Some(r) = &r { match r { ProcessNavResult::SwitchOccurred => { @@ -710,7 +710,7 @@ fn render_damus_mobile( }); }); - app_action + AppResponse::action(app_action).drag(can_take_drag_from) } fn hovering_post_button( @@ -794,7 +794,7 @@ fn render_damus_desktop( app: &mut Damus, app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui, -) -> Option<AppAction> { +) -> AppResponse { let screen_size = ui.ctx().screen_rect().width(); let calc_panel_width = (screen_size / get_active_columns(app_ctx.accounts, &app.decks_cache).num_columns() as f32) @@ -823,11 +823,13 @@ fn timelines_view( sizes: Size, app: &mut Damus, ctx: &mut AppContext<'_>, -) -> Option<AppAction> { +) -> AppResponse { let num_cols = get_active_columns(ctx.accounts, &app.decks_cache).num_columns(); let mut side_panel_action: Option<nav::SwitchingAction> = None; let mut responses = Vec::with_capacity(num_cols); + let mut can_take_drag_from = Vec::new(); + StripBuilder::new(ui) .size(Size::exact(ui::side_panel::SIDE_PANEL_WIDTH)) .sizes(sizes, num_cols) @@ -883,7 +885,9 @@ fn timelines_view( inner.set_right(rect.right() - v_line_stroke.width); inner }; - responses.push(nav::render_nav(col_index, inner_rect, app, ctx, ui)); + let resp = nav::render_nav(col_index, inner_rect, app, ctx, ui); + can_take_drag_from.extend(resp.can_take_drag_from()); + responses.push(resp); // vertical line ui.painter() @@ -937,11 +941,11 @@ fn timelines_view( storage::save_decks_cache(ctx.path, &app.decks_cache); } - app_action + AppResponse::action(app_action).drag(can_take_drag_from) } impl notedeck::App for Damus { - fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { /* self.app .frame_history diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -200,6 +200,13 @@ impl RenderNavResponse { RenderNavResponse { column, response } } + pub fn can_take_drag_from(&self) -> Vec<egui::Id> { + match &self.response { + NotedeckNavResponse::Popup(_) => Vec::new(), // TODO(kernelkind): upgrade once popup supports drag ids + NotedeckNavResponse::Nav(nav_response) => nav_response.can_take_drag_from.clone(), + } + } + #[must_use = "Make sure to save columns if result is true"] pub fn process_render_nav_response( self, diff --git a/crates/notedeck_columns/src/ui/account_login_view.rs b/crates/notedeck_columns/src/ui/account_login_view.rs @@ -6,7 +6,7 @@ use egui::{ }; use egui_winit::clipboard::Clipboard; use enostr::Keypair; -use notedeck::{fonts::get_font_size, tr, AppAction, Localization, NotedeckTextStyle}; +use notedeck::{fonts::get_font_size, tr, Localization, NotedeckTextStyle}; use notedeck_ui::{ app_images, context_menu::{input_context, PasteBehavior}, @@ -173,17 +173,17 @@ pub fn eye_button(ui: &mut egui::Ui, is_visible: bool) -> egui::Response { mod preview { use super::*; - use notedeck::{App, AppContext}; + use notedeck::{App, AppContext, AppResponse}; pub struct AccountLoginPreview { manager: AcquireKeyState, } impl App for AccountLoginPreview { - fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { AccountLoginView::new(&mut self.manager, ctx.clipboard, ctx.i18n).ui(ui); - None + AppResponse::none() } } diff --git a/crates/notedeck_columns/src/ui/configure_deck.rs b/crates/notedeck_columns/src/ui/configure_deck.rs @@ -326,7 +326,7 @@ mod preview { }; use super::ConfigureDeckView; - use notedeck::{App, AppAction, AppContext}; + use notedeck::{App, AppContext, AppResponse}; pub struct ConfigureDeckPreview { state: DeckState, @@ -341,10 +341,10 @@ mod preview { } impl App for ConfigureDeckPreview { - fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { ConfigureDeckView::new(&mut self.state, ctx.i18n).ui(ui); - None + AppResponse::none() } } diff --git a/crates/notedeck_columns/src/ui/edit_deck.rs b/crates/notedeck_columns/src/ui/edit_deck.rs @@ -60,7 +60,7 @@ mod preview { }; use super::EditDeckView; - use notedeck::{App, AppAction, AppContext}; + use notedeck::{App, AppContext, AppResponse}; pub struct EditDeckPreview { state: DeckState, @@ -75,9 +75,9 @@ mod preview { } impl App for EditDeckPreview { - fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { EditDeckView::new(&mut self.state, ctx.i18n).ui(ui); - None + AppResponse::none() } } diff --git a/crates/notedeck_columns/src/ui/note/post.rs b/crates/notedeck_columns/src/ui/note/post.rs @@ -825,7 +825,7 @@ mod preview { use crate::media_upload::Nip94Event; use super::*; - use notedeck::{App, AppAction, AppContext}; + use notedeck::{App, AppContext, AppResponse}; pub struct PostPreview { draft: Draft, @@ -866,7 +866,7 @@ mod preview { } impl App for PostPreview { - fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { let txn = Transaction::new(app.ndb).expect("txn"); let mut note_context = NoteContext { ndb: app.ndb, @@ -893,7 +893,7 @@ mod preview { ) .ui(&txn, ui); - None + AppResponse::none() } } diff --git a/crates/notedeck_columns/src/ui/preview.rs b/crates/notedeck_columns/src/ui/preview.rs @@ -1,4 +1,4 @@ -use notedeck::AppAction; +use notedeck::AppResponse; pub struct PreviewConfig { pub is_mobile: bool, @@ -22,12 +22,8 @@ impl PreviewApp { } impl notedeck::App for PreviewApp { - fn update( - &mut self, - app_ctx: &mut notedeck::AppContext<'_>, - ui: &mut egui::Ui, - ) -> Option<AppAction> { + fn update(&mut self, app_ctx: &mut notedeck::AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { self.view.update(app_ctx, ui); - None + AppResponse::none() } } diff --git a/crates/notedeck_columns/src/ui/relay.rs b/crates/notedeck_columns/src/ui/relay.rs @@ -292,7 +292,7 @@ fn get_relay_infos(pool: &RelayPool) -> Vec<RelayInfo<'_>> { mod preview { use super::*; use crate::test_data::sample_pool; - use notedeck::{App, AppAction, AppContext}; + use notedeck::{App, AppContext, AppResponse}; pub struct RelayViewPreview { pool: RelayPool, @@ -307,11 +307,11 @@ mod preview { } impl App for RelayViewPreview { - fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { self.pool.try_recv(); let mut id_string_map = HashMap::new(); RelayView::new(app.pool, &mut id_string_map, app.i18n).ui(ui); - None + AppResponse::none() } } diff --git a/crates/notedeck_dave/src/lib.rs b/crates/notedeck_dave/src/lib.rs @@ -8,7 +8,7 @@ use egui_wgpu::RenderState; use enostr::KeypairUnowned; use futures::StreamExt; use nostrdb::Transaction; -use notedeck::{AppAction, AppContext, JobsCache}; +use notedeck::{AppAction, AppContext, AppResponse, JobsCache}; use std::collections::HashMap; use std::string::ToString; use std::sync::mpsc::{self, Receiver}; @@ -343,7 +343,7 @@ You are an AI agent for the nostr protocol called Dave, created by Damus. nostr } impl notedeck::App for Dave { - fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { let mut app_action: Option<AppAction> = None; // always insert system prompt if we have no context @@ -374,6 +374,6 @@ impl notedeck::App for Dave { self.send_user_message(ctx, ui.ctx()); } - app_action + AppResponse::action(app_action) } } diff --git a/crates/notedeck_notebook/src/lib.rs b/crates/notedeck_notebook/src/lib.rs @@ -1,7 +1,7 @@ use crate::ui::{edge_ui, node_ui}; use egui::{Pos2, Rect}; use jsoncanvas::JsonCanvas; -use notedeck::{AppAction, AppContext}; +use notedeck::{AppContext, AppResponse}; mod ui; @@ -28,7 +28,7 @@ impl Default for Notebook { } impl notedeck::App for Notebook { - fn update(&mut self, _ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { + fn update(&mut self, _ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> AppResponse { //let app_action: Option<AppAction> = None; if !self.loaded { @@ -48,7 +48,7 @@ impl notedeck::App for Notebook { } }); - None + AppResponse::none() } }