notedeck

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

commit 217c1e52239b4625c88e7427bcbeb05ab3437558
parent 26d027f03e413a3374dfff908a145cf0de9b3fc1
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 10 Jul 2025 17:16:30 -0700

columns/decks: add home and notifications for new accounts

This is way more user friendly, and needed on mobile

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

Diffstat:
Mcrates/notedeck_columns/src/accounts/mod.rs | 46+++++++++++++++++++++++++---------------------
Mcrates/notedeck_columns/src/decks.rs | 103++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mcrates/notedeck_columns/src/nav.rs | 6++----
3 files changed, 95 insertions(+), 60 deletions(-)

diff --git a/crates/notedeck_columns/src/accounts/mod.rs b/crates/notedeck_columns/src/accounts/mod.rs @@ -1,19 +1,19 @@ use enostr::{FullKeypair, Pubkey}; use nostrdb::{Ndb, Transaction}; -use notedeck::{Accounts, Images, SingleUnkIdAction, UnknownIds}; +use notedeck::{Accounts, AppContext, SingleUnkIdAction, UnknownIds}; use crate::app::get_active_columns_mut; use crate::decks::DecksCache; use crate::{ login_manager::AcquireKeyState, route::Route, + timeline::TimelineCache, ui::{ account_login_view::{AccountLoginResponse, AccountLoginView}, accounts::{AccountsView, AccountsViewResponse}, }, }; -use egui_winit::clipboard::Clipboard; use tracing::info; mod route; @@ -63,22 +63,22 @@ pub struct AddAccountAction { #[allow(clippy::too_many_arguments)] pub fn render_accounts_route( ui: &mut egui::Ui, - ndb: &Ndb, + app_ctx: &mut AppContext, col: usize, - img_cache: &mut Images, - accounts: &mut Accounts, decks: &mut DecksCache, + timeline_cache: &mut TimelineCache, login_state: &mut AcquireKeyState, - clipboard: &mut Clipboard, route: AccountsRoute, ) -> AddAccountAction { let resp = match route { - AccountsRoute::Accounts => AccountsView::new(ndb, accounts, img_cache) - .ui(ui) - .inner - .map(AccountsRouteResponse::Accounts), + AccountsRoute::Accounts => { + AccountsView::new(app_ctx.ndb, app_ctx.accounts, app_ctx.img_cache) + .ui(ui) + .inner + .map(AccountsRouteResponse::Accounts) + } - AccountsRoute::AddAccount => AccountLoginView::new(login_state, clipboard) + AccountsRoute::AddAccount => AccountLoginView::new(login_state, app_ctx.clipboard) .ui(ui) .inner .map(AccountsRouteResponse::AddAccount), @@ -87,16 +87,17 @@ pub fn render_accounts_route( if let Some(resp) = resp { match resp { AccountsRouteResponse::Accounts(response) => { - let action = process_accounts_view_response(accounts, decks, col, response); + let action = process_accounts_view_response(app_ctx.accounts, decks, col, response); AddAccountAction { accounts_action: action, unk_id_action: SingleUnkIdAction::no_action(), } } AccountsRouteResponse::AddAccount(response) => { - let action = process_login_view_response(accounts, decks, col, ndb, response); + let action = + process_login_view_response(app_ctx, timeline_cache, decks, col, response); *login_state = Default::default(); - let router = get_active_columns_mut(accounts, decks) + let router = get_active_columns_mut(app_ctx.accounts, decks) .column_mut(col) .router_mut(); router.go_back(); @@ -140,27 +141,30 @@ pub fn process_accounts_view_response( } pub fn process_login_view_response( - manager: &mut Accounts, + app_ctx: &mut AppContext, + timeline_cache: &mut TimelineCache, decks: &mut DecksCache, col: usize, - ndb: &Ndb, response: AccountLoginResponse, ) -> AddAccountAction { let (r, pubkey) = match response { AccountLoginResponse::CreateNew => { let kp = FullKeypair::generate().to_keypair(); let pubkey = kp.pubkey; - let txn = Transaction::new(ndb).expect("txn"); - (manager.add_account(ndb, &txn, kp), pubkey) + let txn = Transaction::new(app_ctx.ndb).expect("txn"); + (app_ctx.accounts.add_account(app_ctx.ndb, &txn, kp), pubkey) } AccountLoginResponse::LoginWith(keypair) => { let pubkey = keypair.pubkey; - let txn = Transaction::new(ndb).expect("txn"); - (manager.add_account(ndb, &txn, keypair), pubkey) + let txn = Transaction::new(app_ctx.ndb).expect("txn"); + ( + app_ctx.accounts.add_account(app_ctx.ndb, &txn, keypair), + pubkey, + ) } }; - decks.add_deck_default(pubkey); + decks.add_deck_default(app_ctx, timeline_cache, pubkey); if let Some(action) = r { AddAccountAction { diff --git a/crates/notedeck_columns/src/decks.rs b/crates/notedeck_columns/src/decks.rs @@ -100,12 +100,27 @@ impl DecksCache { .unwrap_or_else(|| panic!("fallback deck not found")) } - pub fn add_deck_default(&mut self, key: Pubkey) { - self.account_to_decks.insert(key, Decks::default()); + pub fn add_deck_default( + &mut self, + ctx: &mut AppContext, + timeline_cache: &mut TimelineCache, + pubkey: Pubkey, + ) { + let mut decks = Decks::default(); + + // add home and notifications for new accounts + add_demo_columns( + ctx, + timeline_cache, + pubkey, + &mut decks.decks_mut()[0].columns, + ); + + self.account_to_decks.insert(pubkey, decks); info!( "Adding new default deck for {:?}. New decks size is {}", - key, - self.account_to_decks.get(&key).unwrap().decks.len() + pubkey, + self.account_to_decks.get(&pubkey).unwrap().decks.len() ); } @@ -303,20 +318,29 @@ pub struct Deck { impl Default for Deck { fn default() -> Self { - let mut columns = Columns::default(); - columns.new_column_picker(); + let columns = Columns::default(); Self { - icon: '🇩', - name: String::from("Default Deck"), columns, + icon: Deck::default_icon(), + name: Deck::default_name().to_string(), } } } impl Deck { + pub fn default_icon() -> char { + '🇩' + } + + pub fn default_name() -> &'static str { + "Default Deck" + } + pub fn new(icon: char, name: String) -> Self { let mut columns = Columns::default(); + columns.new_column_picker(); + Self { icon, name, @@ -346,6 +370,39 @@ impl Deck { } } +pub fn add_demo_columns( + ctx: &mut AppContext, + timeline_cache: &mut TimelineCache, + pubkey: Pubkey, + columns: &mut Columns, +) { + let timeline_kinds = [ + TimelineKind::contact_list(pubkey), + TimelineKind::notifications(pubkey), + ]; + + let txn = Transaction::new(ctx.ndb).unwrap(); + + for kind in &timeline_kinds { + if let Some(results) = columns.add_new_timeline_column( + timeline_cache, + &txn, + ctx.ndb, + ctx.note_cache, + ctx.pool, + kind, + ) { + results.process( + ctx.ndb, + ctx.note_cache, + &txn, + timeline_cache, + ctx.unknown_ids, + ); + } + } +} + pub fn demo_decks( demo_pubkey: Pubkey, timeline_cache: &mut TimelineCache, @@ -354,37 +411,13 @@ pub fn demo_decks( let deck = { let mut columns = Columns::default(); - let timeline_kinds = [ - TimelineKind::contact_list(demo_pubkey), - TimelineKind::notifications(demo_pubkey), - ]; - - let txn = Transaction::new(ctx.ndb).unwrap(); - - for kind in &timeline_kinds { - if let Some(results) = columns.add_new_timeline_column( - timeline_cache, - &txn, - ctx.ndb, - ctx.note_cache, - ctx.pool, - kind, - ) { - results.process( - ctx.ndb, - ctx.note_cache, - &txn, - timeline_cache, - ctx.unknown_ids, - ); - } - } + add_demo_columns(ctx, timeline_cache, demo_pubkey, &mut columns); //columns.add_new_timeline_column(Timeline::hashtag("introductions".to_string())); Deck { - icon: '🇩', - name: String::from("Demo Deck"), + icon: Deck::default_icon(), + name: Deck::default_name().to_string(), columns, } }; diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -456,13 +456,11 @@ fn render_nav_body( Route::Accounts(amr) => { let mut action = render_accounts_route( ui, - ctx.ndb, + ctx, col, - ctx.img_cache, - ctx.accounts, &mut app.decks_cache, + &mut app.timeline_cache, &mut app.view_state.login, - ctx.clipboard, *amr, ); let txn = Transaction::new(ctx.ndb).expect("txn");