notedeck

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

commit ad90a9565aebd54bd8217170adc2e91d65b6895b
parent 675a223b1114d69fb5889061546db586c57e39b0
Author: kernelkind <kernelkind@gmail.com>
Date:   Mon, 17 Mar 2025 14:45:55 -0400

canonize UserAccount

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

Diffstat:
Mcrates/notedeck/src/accounts.rs | 66++++++++++++++++++++++++++++++++----------------------------------
Mcrates/notedeck/src/user_account.rs | 14++++++++------
Mcrates/notedeck_columns/src/app.rs | 32++++++++++----------------------
Mcrates/notedeck_columns/src/nav.rs | 18+++++++-----------
Mcrates/notedeck_columns/src/ui/accounts.rs | 2+-
Mcrates/notedeck_columns/src/ui/add_column.rs | 20++++++++++----------
Mcrates/notedeck_columns/src/ui/profile/preview.rs | 2+-
Mcrates/notedeck_columns/src/ui/side_panel.rs | 4++--
8 files changed, 71 insertions(+), 87 deletions(-)

diff --git a/crates/notedeck/src/accounts.rs b/crates/notedeck/src/accounts.rs @@ -3,7 +3,7 @@ use tracing::{debug, error, info}; use crate::{ FileKeyStorage, MuteFun, Muted, RelaySpec, SingleUnkIdAction, UnknownIds, UserAccount, }; -use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool}; +use enostr::{ClientMessage, FilledKeypair, Keypair, Pubkey, RelayPool}; use nostrdb::{Filter, Ndb, Note, NoteBuilder, NoteKey, Subscription, Transaction}; use std::cmp::Ordering; use std::collections::{BTreeMap, BTreeSet}; @@ -319,7 +319,7 @@ impl Accounts { pub fn new(key_store: Option<FileKeyStorage>, forced_relays: Vec<String>) -> Self { let accounts = match &key_store { Some(keystore) => match keystore.get_keys() { - Ok(k) => k, + Ok(k) => k.into_iter().map(|key| UserAccount { key }).collect(), Err(e) => { tracing::error!("could not get keys: {e}"); Vec::new() @@ -371,13 +371,15 @@ impl Accounts { } pub fn find_account(&self, pk: &[u8; 32]) -> Option<&UserAccount> { - self.accounts.iter().find(|acc| acc.pubkey.bytes() == pk) + self.accounts + .iter() + .find(|acc| acc.key.pubkey.bytes() == pk) } pub fn remove_account(&mut self, index: usize) { if let Some(account) = self.accounts.get(index) { if let Some(key_store) = &self.key_store { - if let Err(e) = key_store.remove_key(account) { + if let Err(e) = key_store.remove_key(&account.key) { tracing::error!("Could not remove account at index {index}: {e}"); } } @@ -413,8 +415,8 @@ impl Accounts { fn contains_account(&self, pubkey: &[u8; 32]) -> Option<ContainsAccount> { for (index, account) in self.accounts.iter().enumerate() { - let has_pubkey = account.pubkey.bytes() == pubkey; - let has_nsec = account.secret_key.is_some(); + let has_pubkey = account.key.pubkey.bytes() == pubkey; + let has_nsec = account.key.secret_key.is_some(); if has_pubkey { return Some(ContainsAccount { has_nsec, index }); } @@ -447,7 +449,7 @@ impl Accounts { } } - self.accounts[contains_acc.index] = account; + self.accounts[contains_acc.index].key = account; } else { info!("already have account, not adding {}", pubkey); } @@ -459,7 +461,7 @@ impl Accounts { tracing::error!("Could not add key for {:?}: {e}", account.pubkey); } } - self.accounts.push(account); + self.accounts.push(UserAccount::new(account)); self.accounts.len() - 1 }; @@ -483,33 +485,27 @@ impl Accounts { pub fn selected_or_first_nsec(&self) -> Option<FilledKeypair<'_>> { self.get_selected_account() - .and_then(|kp| kp.to_full()) - .or_else(|| self.accounts.iter().find_map(|a| a.to_full())) + .and_then(|kp| kp.key.to_full()) + .or_else(|| self.accounts.iter().find_map(|a| a.key.to_full())) } /// Get the selected account's pubkey as bytes. Common operation so /// we make it a helper here. pub fn selected_account_pubkey_bytes(&self) -> Option<&[u8; 32]> { - self.get_selected_account().map(|kp| kp.pubkey.bytes()) + self.get_selected_account().map(|kp| kp.key.pubkey.bytes()) + } + + pub fn selected_account_pubkey(&self) -> Option<&Pubkey> { + self.get_selected_account().map(|acc| &acc.key.pubkey) } pub fn get_selected_account(&self) -> Option<&UserAccount> { - if let Some(account_index) = self.currently_selected_account { - if let Some(account) = self.get_account(account_index) { - Some(account) - } else { - None - } - } else { - None - } + self.currently_selected_account + .map(|i| self.get_account(i))? } pub fn get_selected_account_data(&mut self) -> Option<&mut AccountData> { - let account_pubkey = { - let account = self.get_selected_account()?; - *account.pubkey.bytes() - }; + let account_pubkey = *self.selected_account_pubkey_bytes()?; self.account_data.get_mut(&account_pubkey) } @@ -517,8 +513,8 @@ impl Accounts { if let Some(account) = self.accounts.get(index) { self.currently_selected_account = Some(index); if let Some(key_store) = &self.key_store { - if let Err(e) = key_store.select_key(Some(account.pubkey)) { - tracing::error!("Could not select key {:?}: {e}", account.pubkey); + if let Err(e) = key_store.select_key(Some(account.key.pubkey)) { + tracing::error!("Could not select key {:?}: {e}", account.key.pubkey); } } } @@ -536,7 +532,7 @@ impl Accounts { pub fn mutefun(&self) -> Box<MuteFun> { if let Some(index) = self.currently_selected_account { if let Some(account) = self.accounts.get(index) { - let pubkey = account.pubkey.bytes(); + let pubkey = account.key.pubkey.bytes(); if let Some(account_data) = self.account_data.get(pubkey) { let muted = Arc::clone(&account_data.muted.muted); return Box::new(move |note: &Note, thread: &[u8; 32]| { @@ -571,7 +567,7 @@ impl Accounts { // which have still data but are no longer in our account list (removed). fn delta_accounts(&self) -> (Vec<[u8; 32]>, Vec<[u8; 32]>) { let mut added = Vec::new(); - for pubkey in self.accounts.iter().map(|a| a.pubkey.bytes()) { + for pubkey in self.accounts.iter().map(|a| a.key.pubkey.bytes()) { if !self.account_data.contains_key(pubkey) { added.push(*pubkey); } @@ -641,7 +637,7 @@ impl Accounts { debug!( "updating relay configuration for currently selected {:?}", self.currently_selected_account - .map(|i| hex::encode(self.accounts.get(i).unwrap().pubkey.bytes())) + .map(|i| hex::encode(self.accounts.get(i).unwrap().key.pubkey.bytes())) ); // If forced relays are set use them only @@ -704,7 +700,7 @@ impl Accounts { for (ndx, account) in self.accounts.iter().enumerate() { if Some(ndx) != self.currently_selected_account { // this account is not currently selected - if let Some(data) = self.account_data.get_mut(account.pubkey.bytes()) { + if let Some(data) = self.account_data.get_mut(account.key.pubkey.bytes()) { if data.relay.sub.is_some() { // this account has relay subs, deactivate them data.relay.deactivate(ndb, pool); @@ -754,7 +750,7 @@ impl Accounts { if let Some(contains) = self.contains_account(pubkey) { if contains.has_nsec { if let Some(kp) = self.get_account(contains.index) { - return kp.to_full(); + return kp.key.to_full(); } } } @@ -778,7 +774,7 @@ impl Accounts { Some(index) => match self.accounts.get(index) { None => error!("selected account index {} is out of range.", index), Some(keypair) => { - let key_bytes: [u8; 32] = *keypair.pubkey.bytes(); + let key_bytes: [u8; 32] = *keypair.key.pubkey.bytes(); match self.account_data.get_mut(&key_bytes) { None => error!("no account data found for the provided key."), Some(account_data) => { @@ -799,7 +795,7 @@ impl Accounts { self.needs_relay_config = true; // If we have the secret key publish the NIP-65 relay list - if let Some(secretkey) = &keypair.secret_key { + if let Some(secretkey) = &keypair.key.secret_key { account_data .relay .publish_nip65_relays(&secretkey.to_secret_bytes(), pool); @@ -828,7 +824,9 @@ enum RelayAction { fn get_selected_index(accounts: &[UserAccount], keystore: &FileKeyStorage) -> Option<usize> { match keystore.get_selected_key() { Ok(Some(pubkey)) => { - return accounts.iter().position(|account| account.pubkey == pubkey); + return accounts + .iter() + .position(|account| account.key.pubkey == pubkey); } Ok(None) => {} Err(e) => error!("Error getting selected key: {}", e), diff --git a/crates/notedeck/src/user_account.rs b/crates/notedeck/src/user_account.rs @@ -1,9 +1,11 @@ use enostr::Keypair; -//pub struct UserAccount { -//pub key: Keypair, -//pub relays: RelayPool, -//pub relays: Vec<String>, -//} +pub struct UserAccount { + pub key: Keypair, +} -pub type UserAccount = Keypair; +impl UserAccount { + pub fn new(key: Keypair) -> Self { + Self { key } + } +} diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs @@ -372,19 +372,10 @@ impl Damus { pub fn new(ctx: &mut AppContext<'_>, args: &[String]) -> Self { // arg parsing - let (parsed_args, unrecognized_args) = ColumnsArgs::parse( - args, - ctx.accounts - .get_selected_account() - .as_ref() - .map(|kp| &kp.pubkey), - ); + let (parsed_args, unrecognized_args) = + ColumnsArgs::parse(args, ctx.accounts.selected_account_pubkey()); - let account = ctx - .accounts - .get_selected_account() - .as_ref() - .map(|a| a.pubkey.bytes()); + let account = ctx.accounts.selected_account_pubkey_bytes(); let mut timeline_cache = TimelineCache::default(); let tmp_columns = !parsed_args.columns.is_empty(); @@ -425,7 +416,7 @@ impl Damus { info!("DecksCache: creating new with demo configuration"); let mut cache = DecksCache::new_with_demo_config(&mut timeline_cache, ctx); for account in ctx.accounts.get_accounts() { - cache.add_deck_default(account.pubkey); + cache.add_deck_default(account.key.pubkey); } set_demo(&mut cache, ctx.ndb, ctx.accounts, ctx.unknown_ids); @@ -657,11 +648,9 @@ pub fn get_active_columns<'a>(accounts: &Accounts, decks_cache: &'a DecksCache) } pub fn get_decks<'a>(accounts: &Accounts, decks_cache: &'a DecksCache) -> &'a Decks { - let key = if let Some(acc) = accounts.get_selected_account() { - &acc.pubkey - } else { - decks_cache.get_fallback_pubkey() - }; + let key = accounts + .selected_account_pubkey() + .unwrap_or_else(|| decks_cache.get_fallback_pubkey()); decks_cache.decks(key) } @@ -675,10 +664,9 @@ pub fn get_active_columns_mut<'a>( } pub fn get_decks_mut<'a>(accounts: &Accounts, decks_cache: &'a mut DecksCache) -> &'a mut Decks { - if let Some(acc) = accounts.get_selected_account() { - decks_cache.decks_mut(&acc.pubkey) - } else { - decks_cache.fallback_mut() + match accounts.selected_account_pubkey() { + Some(acc) => decks_cache.decks_mut(acc), + None => decks_cache.fallback_mut(), } } diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -370,7 +370,7 @@ fn render_nav_body( } Route::ComposeNote => { - let kp = ctx.accounts.get_selected_account()?.to_full()?; + let kp = ctx.accounts.get_selected_account()?.key.to_full()?; let draft = app.drafts.compose_mut(); let txn = Transaction::new(ctx.ndb).expect("txn"); @@ -433,11 +433,9 @@ fn render_nav_body( let new_deck_state = app.view_state.id_to_deck_state.entry(id).or_default(); let mut resp = None; if let Some(config_resp) = ConfigureDeckView::new(new_deck_state).ui(ui) { - if let Some(cur_acc) = ctx.accounts.get_selected_account() { - app.decks_cache.add_deck( - cur_acc.pubkey, - Deck::new(config_resp.icon, config_resp.name), - ); + if let Some(cur_acc) = ctx.accounts.selected_account_pubkey() { + app.decks_cache + .add_deck(*cur_acc, Deck::new(config_resp.icon, config_resp.name)); // set new deck as active let cur_index = get_decks_mut(ctx.accounts, &mut app.decks_cache) @@ -462,11 +460,9 @@ fn render_nav_body( .decks_mut() .get_mut(*index) .expect("index wasn't valid"); - let id = ui.id().with(( - "edit-deck", - ctx.accounts.get_selected_account().map(|k| k.pubkey), - index, - )); + let id = ui + .id() + .with(("edit-deck", ctx.accounts.selected_account_pubkey(), index)); let deck_state = app .view_state .id_to_deck_state diff --git a/crates/notedeck_columns/src/ui/accounts.rs b/crates/notedeck_columns/src/ui/accounts.rs @@ -69,7 +69,7 @@ impl<'a> AccountsView<'a> { for i in 0..accounts.num_accounts() { let (account_pubkey, has_nsec) = match accounts.get_account(i) { - Some(acc) => (acc.pubkey.bytes(), acc.secret_key.is_some()), + Some(acc) => (acc.key.pubkey.bytes(), acc.key.secret_key.is_some()), None => continue, }; diff --git a/crates/notedeck_columns/src/ui/add_column.rs b/crates/notedeck_columns/src/ui/add_column.rs @@ -143,18 +143,18 @@ impl AddColumnOption { AddColumnOption::Algo(algo_option) => AddColumnResponse::Algo(algo_option), AddColumnOption::Universe => AddColumnResponse::Timeline(TimelineKind::Universe), AddColumnOption::Notification(pubkey) => AddColumnResponse::Timeline( - TimelineKind::Notifications(*pubkey.as_pubkey(&cur_account.pubkey)), + TimelineKind::Notifications(*pubkey.as_pubkey(&cur_account.key.pubkey)), ), AddColumnOption::UndecidedNotification => AddColumnResponse::UndecidedNotification, AddColumnOption::Contacts(pk_src) => AddColumnResponse::Timeline( - TimelineKind::contact_list(*pk_src.as_pubkey(&cur_account.pubkey)), + TimelineKind::contact_list(*pk_src.as_pubkey(&cur_account.key.pubkey)), ), AddColumnOption::ExternalNotification => AddColumnResponse::ExternalNotification, AddColumnOption::UndecidedHashtag => AddColumnResponse::Hashtag, AddColumnOption::UndecidedIndividual => AddColumnResponse::UndecidedIndividual, AddColumnOption::ExternalIndividual => AddColumnResponse::ExternalIndividual, AddColumnOption::Individual(pubkey_source) => AddColumnResponse::Timeline( - TimelineKind::profile(*pubkey_source.as_pubkey(&cur_account.pubkey)), + TimelineKind::profile(*pubkey_source.as_pubkey(&cur_account.key.pubkey)), ), } } @@ -453,10 +453,10 @@ impl<'a> AddColumnView<'a> { }); if let Some(acc) = self.cur_account { - let source = if acc.secret_key.is_some() { + let source = if acc.key.secret_key.is_some() { PubkeySource::DeckAuthor } else { - PubkeySource::Explicit(acc.pubkey) + PubkeySource::Explicit(acc.key.pubkey) }; vec.push(ColumnOptionData { @@ -498,10 +498,10 @@ impl<'a> AddColumnView<'a> { let mut vec = Vec::new(); if let Some(acc) = self.cur_account { - let source = if acc.secret_key.is_some() { + let source = if acc.key.secret_key.is_some() { PubkeySource::DeckAuthor } else { - PubkeySource::Explicit(acc.pubkey) + PubkeySource::Explicit(acc.key.pubkey) }; vec.push(ColumnOptionData { @@ -528,10 +528,10 @@ impl<'a> AddColumnView<'a> { let mut vec = Vec::new(); if let Some(acc) = self.cur_account { - let source = if acc.secret_key.is_some() { + let source = if acc.key.secret_key.is_some() { PubkeySource::DeckAuthor } else { - PubkeySource::Explicit(acc.pubkey) + PubkeySource::Explicit(acc.key.pubkey) }; vec.push(ColumnOptionData { @@ -606,7 +606,7 @@ pub fn render_add_column_routes( AddAlgoRoute::Base => add_column_view.algo_ui(ui), AddAlgoRoute::LastPerPubkey => { if let Some(deck_author) = ctx.accounts.get_selected_account() { - add_column_view.algo_last_per_pk_ui(ui, deck_author.pubkey) + add_column_view.algo_last_per_pk_ui(ui, deck_author.key.pubkey) } else { None } diff --git a/crates/notedeck_columns/src/ui/profile/preview.rs b/crates/notedeck_columns/src/ui/profile/preview.rs @@ -166,7 +166,7 @@ pub fn get_account_url<'a>( account: Option<&UserAccount>, ) -> &'a str { if let Some(selected_account) = account { - if let Ok(profile) = ndb.get_profile_by_pubkey(txn, selected_account.pubkey.bytes()) { + if let Ok(profile) = ndb.get_profile_by_pubkey(txn, selected_account.key.pubkey.bytes()) { get_profile_url_owned(Some(profile)) } else { get_profile_url_owned(None) diff --git a/crates/notedeck_columns/src/ui/side_panel.rs b/crates/notedeck_columns/src/ui/side_panel.rs @@ -111,7 +111,7 @@ impl<'a> DesktopSidePanel<'a> { ui.add_space(16.0); let is_interactive = self .selected_account - .is_some_and(|s| s.secret_key.is_some()); + .is_some_and(|s| s.key.secret_key.is_some()); let compose_resp = ui.add(compose_note_button(is_interactive, dark_mode)); let compose_resp = if is_interactive { compose_resp @@ -599,7 +599,7 @@ fn show_decks<'a>( ) -> InnerResponse<Option<usize>> { let show_decks_id = ui.id().with("show-decks"); let account_id = if let Some(acc) = selected_account { - acc.pubkey + acc.key.pubkey } else { *decks_cache.get_fallback_pubkey() };