notedeck

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

commit b41f4c33591da82a89650dd324029d083cef4d0b
parent 10c4ac80a1ad445945a20953b10422e0576d8e0c
Author: kernelkind <kernelkind@gmail.com>
Date:   Tue,  1 Jul 2025 15:09:10 -0400

decouple `RelayView` UI from state mutation

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

Diffstat:
Mcrates/notedeck/src/account/accounts.rs | 26+++++++++++---------------
Mcrates/notedeck/src/lib.rs | 1+
Mcrates/notedeck_columns/src/lib.rs | 1-
Mcrates/notedeck_columns/src/nav.rs | 22++++++++++------------
Dcrates/notedeck_columns/src/relay_pool_manager.rs | 60------------------------------------------------------------
Mcrates/notedeck_columns/src/ui/relay.rs | 58+++++++++++++++++++++++++++++++---------------------------
6 files changed, 53 insertions(+), 115 deletions(-)

diff --git a/crates/notedeck/src/account/accounts.rs b/crates/notedeck/src/account/accounts.rs @@ -315,25 +315,21 @@ impl Accounts { self.cache.get(pubkey).and_then(|r| r.key.to_full()) } - pub fn add_advertised_relay(&mut self, relay_to_add: &str, pool: &mut RelayPool) { + pub fn process_relay_action( + &mut self, + ctx: &egui::Context, + pool: &mut RelayPool, + action: RelayAction, + ) { let acc = self.cache.selected_mut(); - modify_advertised_relays( - &acc.key, - RelayAction::Add(relay_to_add.to_owned()), - pool, - &self.relay_defaults, - &mut acc.data, - ); - } + modify_advertised_relays(&acc.key, action, pool, &self.relay_defaults, &mut acc.data); - pub fn remove_advertised_relay(&mut self, relay_to_remove: &str, pool: &mut RelayPool) { - let acc = self.cache.selected_mut(); - modify_advertised_relays( - &acc.key, - RelayAction::Remove(relay_to_remove.to_owned()), + update_relay_configuration( pool, &self.relay_defaults, - &mut acc.data, + &acc.key.pubkey, + &acc.data, + create_wakeup(ctx), ); } } diff --git a/crates/notedeck/src/lib.rs b/crates/notedeck/src/lib.rs @@ -34,6 +34,7 @@ mod wallet; mod zaps; pub use account::accounts::{AccountData, Accounts}; +pub use account::relay::RelayAction; pub use account::FALLBACK_PUBKEY; pub use app::{App, AppAction, Notedeck}; pub use args::Args; diff --git a/crates/notedeck_columns/src/lib.rs b/crates/notedeck_columns/src/lib.rs @@ -20,7 +20,6 @@ mod nav; mod post; mod profile; mod profile_state; -pub mod relay_pool_manager; mod route; mod search; mod subscriptions; diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -6,7 +6,6 @@ use crate::{ decks::{Deck, DecksAction, DecksCache}, profile::{ProfileAction, SaveProfileChanges}, profile_state::ProfileState, - relay_pool_manager::RelayPoolManager, route::{Route, Router, SingletonRouter}, timeline::{ route::{render_thread_route, render_timeline_route}, @@ -31,9 +30,8 @@ use crate::{ use egui_nav::{Nav, NavAction, NavResponse, NavUiType, Percent, PopupResponse, PopupSheet}; use nostrdb::Transaction; use notedeck::{ - get_current_default_msats, get_current_wallet, AppContext, NoteAction, NoteContext, + get_current_default_msats, get_current_wallet, AppContext, NoteAction, NoteContext, RelayAction, }; -use notedeck_ui::View; use tracing::error; /// The result of processing a nav response @@ -59,6 +57,7 @@ pub enum RenderNavAction { ProfileAction(ProfileAction), SwitchingAction(SwitchingAction), WalletAction(WalletAction), + RelayAction(RelayAction), } pub enum SwitchingAction { @@ -334,7 +333,6 @@ fn process_render_nav_action( let router_action = match action { RenderNavAction::Back => Some(RouterAction::GoBack), RenderNavAction::PfpClicked => Some(RouterAction::PfpClicked), - RenderNavAction::RemoveColumn => { let kinds_to_pop = app.columns_mut(ctx.accounts).delete_column(col); @@ -346,7 +344,6 @@ fn process_render_nav_action( return Some(ProcessNavResult::SwitchOccurred); } - RenderNavAction::PostAction(new_post_action) => { let txn = Transaction::new(ctx.ndb).expect("txn"); match new_post_action.execute(ctx.ndb, &txn, ctx.pool, &mut app.drafts) { @@ -356,7 +353,6 @@ fn process_render_nav_action( Some(RouterAction::GoBack) } - RenderNavAction::NoteAction(note_action) => { let txn = Transaction::new(ctx.ndb).expect("txn"); @@ -378,7 +374,6 @@ fn process_render_nav_action( ui, ) } - RenderNavAction::SwitchingAction(switching_action) => { if switching_action.process( &mut app.timeline_cache, @@ -399,6 +394,11 @@ fn process_render_nav_action( RenderNavAction::WalletAction(wallet_action) => { wallet_action.process(ctx.accounts, ctx.global_wallet) } + RenderNavAction::RelayAction(action) => { + ctx.accounts + .process_relay_action(ui.ctx(), ctx.pool, action); + None + } }; if let Some(action) = router_action { @@ -471,11 +471,9 @@ fn render_nav_body( .accounts_action .map(|f| RenderNavAction::SwitchingAction(SwitchingAction::Accounts(f))) } - Route::Relays => { - let manager = RelayPoolManager::new(ctx.pool); - RelayView::new(ctx.accounts, manager, &mut app.view_state.id_string_map).ui(ui); - None - } + Route::Relays => RelayView::new(ctx.pool, &mut app.view_state.id_string_map) + .ui(ui) + .map(RenderNavAction::RelayAction), Route::Reply(id) => { let txn = if let Ok(txn) = Transaction::new(ctx.ndb) { txn diff --git a/crates/notedeck_columns/src/relay_pool_manager.rs b/crates/notedeck_columns/src/relay_pool_manager.rs @@ -1,60 +0,0 @@ -use enostr::RelayPool; -pub use enostr::RelayStatus; - -/// The interface to a RelayPool for UI components. -/// Represents all user-facing operations that can be performed for a user's relays -pub struct RelayPoolManager<'a> { - pub pool: &'a mut RelayPool, -} - -pub struct RelayInfo<'a> { - pub relay_url: &'a str, - pub status: RelayStatus, -} - -impl<'a> RelayPoolManager<'a> { - pub fn new(pool: &'a mut RelayPool) -> Self { - RelayPoolManager { pool } - } - - pub fn get_relay_infos(&self) -> Vec<RelayInfo> { - self.pool - .relays - .iter() - .map(|relay| RelayInfo { - relay_url: relay.url(), - status: relay.status(), - }) - .collect() - } - - /// index of the Vec<RelayInfo> from get_relay_infos - pub fn remove_relay(&mut self, index: usize) { - if index < self.pool.relays.len() { - self.pool.relays.remove(index); - } - } - - /// removes all specified relay indicies shown in get_relay_infos - pub fn remove_relays(&mut self, mut indices: Vec<usize>) { - indices.sort_unstable_by(|a, b| b.cmp(a)); - indices.iter().for_each(|index| self.remove_relay(*index)); - } - - // FIXME - this is not ever called? - pub fn add_relay(&mut self, ctx: &egui::Context, relay_url: String) { - let _ = self.pool.add_url(relay_url, create_wakeup(ctx)); - } - - /// check whether a relay url is valid - pub fn is_valid_relay(&self, url: &str) -> bool { - self.pool.is_valid_url(url) - } -} - -pub fn create_wakeup(ctx: &egui::Context) -> impl Fn() + Send + Sync + Clone + 'static { - let ctx = ctx.clone(); - move || { - ctx.request_repaint(); - } -} diff --git a/crates/notedeck_columns/src/ui/relay.rs b/crates/notedeck_columns/src/ui/relay.rs @@ -1,24 +1,23 @@ use std::collections::HashMap; -use crate::relay_pool_manager::{RelayPoolManager, RelayStatus}; use crate::ui::{Preview, PreviewConfig}; use egui::{Align, Button, CornerRadius, Frame, Id, Layout, Margin, Rgba, RichText, Ui, Vec2}; -use enostr::RelayPool; -use notedeck::{Accounts, NotedeckTextStyle}; +use enostr::{RelayPool, RelayStatus}; +use notedeck::{NotedeckTextStyle, RelayAction}; use notedeck_ui::app_images; -use notedeck_ui::{colors::PINK, padding, View}; +use notedeck_ui::{colors::PINK, padding}; use tracing::debug; use super::widgets::styled_button; pub struct RelayView<'a> { - accounts: &'a mut Accounts, - manager: RelayPoolManager<'a>, + pool: &'a RelayPool, id_string_map: &'a mut HashMap<Id, String>, } -impl View for RelayView<'_> { - fn ui(&mut self, ui: &mut egui::Ui) { +impl RelayView<'_> { + pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<RelayAction> { + let mut action = None; Frame::new() .inner_margin(Margin::symmetric(10, 0)) .show(ui, |ui| { @@ -40,28 +39,23 @@ impl View for RelayView<'_> { .auto_shrink([false; 2]) .show(ui, |ui| { if let Some(relay_to_remove) = self.show_relays(ui) { - self.accounts - .remove_advertised_relay(&relay_to_remove, self.manager.pool); + action = Some(RelayAction::Remove(relay_to_remove)); } ui.add_space(8.0); if let Some(relay_to_add) = self.show_add_relay_ui(ui) { - self.accounts - .add_advertised_relay(&relay_to_add, self.manager.pool); + action = Some(RelayAction::Add(relay_to_add)); } }); }); + + action } } impl<'a> RelayView<'a> { - pub fn new( - accounts: &'a mut Accounts, - manager: RelayPoolManager<'a>, - id_string_map: &'a mut HashMap<Id, String>, - ) -> Self { + pub fn new(pool: &'a RelayPool, id_string_map: &'a mut HashMap<Id, String>) -> Self { RelayView { - accounts, - manager, + pool, id_string_map, } } @@ -73,7 +67,7 @@ impl<'a> RelayView<'a> { /// Show the current relays and return a relay the user selected to delete fn show_relays(&'a self, ui: &mut Ui) -> Option<String> { let mut relay_to_remove = None; - for (index, relay_info) in self.manager.get_relay_infos().iter().enumerate() { + for (index, relay_info) in get_relay_infos(self.pool).iter().enumerate() { ui.add_space(8.0); ui.vertical_centered_justified(|ui| { relay_frame(ui).show(ui, |ui| { @@ -153,7 +147,7 @@ impl<'a> RelayView<'a> { .id_string_map .entry(id) .or_insert_with(|| Self::RELAY_PREFILL.to_string()); - let is_enabled = self.manager.is_valid_relay(text_buffer); + let is_enabled = self.pool.is_valid_url(text_buffer); let text_edit = egui::TextEdit::singleline(text_buffer) .hint_text( RichText::new("Enter the relay here") @@ -254,6 +248,21 @@ fn get_connection_icon(status: RelayStatus) -> egui::Image<'static> { } } +struct RelayInfo<'a> { + pub relay_url: &'a str, + pub status: RelayStatus, +} + +fn get_relay_infos(pool: &RelayPool) -> Vec<RelayInfo> { + pool.relays + .iter() + .map(|relay| RelayInfo { + relay_url: relay.url(), + status: relay.status(), + }) + .collect() +} + // PREVIEWS mod preview { @@ -277,12 +286,7 @@ mod preview { fn update(&mut self, app: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> { self.pool.try_recv(); let mut id_string_map = HashMap::new(); - RelayView::new( - app.accounts, - RelayPoolManager::new(&mut self.pool), - &mut id_string_map, - ) - .ui(ui); + RelayView::new(app.pool, &mut id_string_map).ui(ui); None } }