notedeck

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

decks.rs (8737B)


      1 use std::collections::HashMap;
      2 
      3 use enostr::Pubkey;
      4 use nostrdb::Ndb;
      5 use tracing::{error, info};
      6 
      7 use crate::{
      8     accounts::AccountsRoute,
      9     column::{Column, Columns},
     10     route::Route,
     11     timeline::{self, Timeline, TimelineKind},
     12     ui::{add_column::AddColumnRoute, configure_deck::ConfigureDeckResponse},
     13 };
     14 
     15 static FALLBACK_PUBKEY: &str = "aa733081e4f0f79dd43023d8983265593f2b41a988671cfcef3f489b91ad93fe";
     16 
     17 //pub enum DecksAction {
     18 //    Switch(usize),
     19 //    Removing(usize),
     20 //}
     21 
     22 pub struct DecksCache {
     23     pub account_to_decks: HashMap<Pubkey, Decks>,
     24     pub fallback_pubkey: Pubkey,
     25 }
     26 
     27 impl Default for DecksCache {
     28     fn default() -> Self {
     29         let mut account_to_decks: HashMap<Pubkey, Decks> = Default::default();
     30         account_to_decks.insert(Pubkey::from_hex(FALLBACK_PUBKEY).unwrap(), Decks::default());
     31         DecksCache::new(account_to_decks)
     32     }
     33 }
     34 
     35 impl DecksCache {
     36     pub fn new(account_to_decks: HashMap<Pubkey, Decks>) -> Self {
     37         let fallback_pubkey = Pubkey::from_hex(FALLBACK_PUBKEY).unwrap();
     38 
     39         Self {
     40             account_to_decks,
     41             fallback_pubkey,
     42         }
     43     }
     44 
     45     pub fn new_with_demo_config(ndb: &Ndb) -> Self {
     46         let mut account_to_decks: HashMap<Pubkey, Decks> = Default::default();
     47         let fallback_pubkey = Pubkey::from_hex(FALLBACK_PUBKEY).unwrap();
     48         account_to_decks.insert(fallback_pubkey, demo_decks(fallback_pubkey, ndb));
     49         DecksCache::new(account_to_decks)
     50     }
     51 
     52     pub fn decks(&self, key: &Pubkey) -> &Decks {
     53         self.account_to_decks
     54             .get(key)
     55             .unwrap_or_else(|| panic!("{:?} not found", key))
     56     }
     57 
     58     pub fn decks_mut(&mut self, key: &Pubkey) -> &mut Decks {
     59         self.account_to_decks
     60             .get_mut(key)
     61             .unwrap_or_else(|| panic!("{:?} not found", key))
     62     }
     63 
     64     pub fn fallback_mut(&mut self) -> &mut Decks {
     65         self.account_to_decks
     66             .get_mut(&self.fallback_pubkey)
     67             .unwrap_or_else(|| panic!("fallback deck not found"))
     68     }
     69 
     70     pub fn add_deck_default(&mut self, key: Pubkey) {
     71         self.account_to_decks.insert(key, Decks::default());
     72         info!(
     73             "Adding new default deck for {:?}. New decks size is {}",
     74             key,
     75             self.account_to_decks.get(&key).unwrap().decks.len()
     76         );
     77     }
     78 
     79     pub fn add_decks(&mut self, key: Pubkey, decks: Decks) {
     80         self.account_to_decks.insert(key, decks);
     81         info!(
     82             "Adding new deck for {:?}. New decks size is {}",
     83             key,
     84             self.account_to_decks.get(&key).unwrap().decks.len()
     85         );
     86     }
     87 
     88     pub fn add_deck(&mut self, key: Pubkey, deck: Deck) {
     89         match self.account_to_decks.entry(key) {
     90             std::collections::hash_map::Entry::Occupied(mut entry) => {
     91                 let decks = entry.get_mut();
     92                 decks.add_deck(deck);
     93                 info!(
     94                     "Created new deck for {:?}. New number of decks is {}",
     95                     key,
     96                     decks.decks.len()
     97                 );
     98             }
     99             std::collections::hash_map::Entry::Vacant(entry) => {
    100                 info!("Created first deck for {:?}", key);
    101                 entry.insert(Decks::new(deck));
    102             }
    103         }
    104     }
    105 
    106     pub fn remove_for(&mut self, key: &Pubkey) {
    107         info!("Removing decks for {:?}", key);
    108         self.account_to_decks.remove(key);
    109     }
    110 }
    111 
    112 pub struct Decks {
    113     active_deck: usize,
    114     removal_request: Option<usize>,
    115     decks: Vec<Deck>,
    116 }
    117 
    118 impl Default for Decks {
    119     fn default() -> Self {
    120         Decks::new(Deck::default())
    121     }
    122 }
    123 
    124 impl Decks {
    125     pub fn new(deck: Deck) -> Self {
    126         let decks = vec![deck];
    127 
    128         Decks {
    129             active_deck: 0,
    130             removal_request: None,
    131             decks,
    132         }
    133     }
    134 
    135     pub fn from_decks(active_deck: usize, decks: Vec<Deck>) -> Self {
    136         Self {
    137             active_deck,
    138             removal_request: None,
    139             decks,
    140         }
    141     }
    142 
    143     pub fn active(&self) -> &Deck {
    144         self.decks
    145             .get(self.active_deck)
    146             .expect("active_deck index was invalid")
    147     }
    148 
    149     pub fn active_mut(&mut self) -> &mut Deck {
    150         self.decks
    151             .get_mut(self.active_deck)
    152             .expect("active_deck index was invalid")
    153     }
    154 
    155     pub fn decks(&self) -> &Vec<Deck> {
    156         &self.decks
    157     }
    158 
    159     pub fn decks_mut(&mut self) -> &mut Vec<Deck> {
    160         &mut self.decks
    161     }
    162 
    163     pub fn add_deck(&mut self, deck: Deck) {
    164         self.decks.push(deck);
    165     }
    166 
    167     pub fn active_index(&self) -> usize {
    168         self.active_deck
    169     }
    170 
    171     pub fn set_active(&mut self, index: usize) {
    172         if index < self.decks.len() {
    173             self.active_deck = index;
    174         } else {
    175             error!(
    176                 "requested deck change that is invalid. decks len: {}, requested index: {}",
    177                 self.decks.len(),
    178                 index
    179             );
    180         }
    181     }
    182 
    183     pub fn remove_deck(&mut self, index: usize) {
    184         if index < self.decks.len() {
    185             if self.decks.len() > 1 {
    186                 self.decks.remove(index);
    187 
    188                 let info_prefix = format!("Removed deck at index {}", index);
    189                 match index.cmp(&self.active_deck) {
    190                     std::cmp::Ordering::Less => {
    191                         info!(
    192                             "{}. The active deck was index {}, now it is {}",
    193                             info_prefix,
    194                             self.active_deck,
    195                             self.active_deck - 1
    196                         );
    197                         self.active_deck -= 1
    198                     }
    199                     std::cmp::Ordering::Greater => {
    200                         info!(
    201                             "{}. Active deck remains at index {}.",
    202                             info_prefix, self.active_deck
    203                         )
    204                     }
    205                     std::cmp::Ordering::Equal => {
    206                         if index != 0 {
    207                             info!(
    208                                 "{}. Active deck was index {}, now it is {}",
    209                                 info_prefix,
    210                                 self.active_deck,
    211                                 self.active_deck - 1
    212                             );
    213                             self.active_deck -= 1;
    214                         } else {
    215                             info!(
    216                                 "{}. Active deck remains at index {}.",
    217                                 info_prefix, self.active_deck
    218                             )
    219                         }
    220                     }
    221                 }
    222                 self.removal_request = None;
    223             } else {
    224                 error!("attempted unsucessfully to remove the last deck for this account");
    225             }
    226         } else {
    227             error!("index was out of bounds");
    228         }
    229     }
    230 }
    231 
    232 pub struct Deck {
    233     pub icon: char,
    234     pub name: String,
    235     columns: Columns,
    236 }
    237 
    238 impl Default for Deck {
    239     fn default() -> Self {
    240         let mut columns = Columns::default();
    241         columns.new_column_picker();
    242         Self {
    243             icon: '🇩',
    244             name: String::from("Default Deck"),
    245             columns,
    246         }
    247     }
    248 }
    249 
    250 impl Deck {
    251     pub fn new(icon: char, name: String) -> Self {
    252         let mut columns = Columns::default();
    253         columns.new_column_picker();
    254         Self {
    255             icon,
    256             name,
    257             columns,
    258         }
    259     }
    260 
    261     pub fn new_with_columns(icon: char, name: String, columns: Columns) -> Self {
    262         Self {
    263             icon,
    264             name,
    265             columns,
    266         }
    267     }
    268 
    269     pub fn columns(&self) -> &Columns {
    270         &self.columns
    271     }
    272 
    273     pub fn columns_mut(&mut self) -> &mut Columns {
    274         &mut self.columns
    275     }
    276 
    277     pub fn edit(&mut self, changes: ConfigureDeckResponse) {
    278         self.name = changes.name;
    279         self.icon = changes.icon;
    280     }
    281 }
    282 
    283 pub fn demo_decks(demo_pubkey: Pubkey, ndb: &Ndb) -> Decks {
    284     let deck = {
    285         let mut columns = Columns::default();
    286         columns.add_column(Column::new(vec![
    287             Route::AddColumn(AddColumnRoute::Base),
    288             Route::Accounts(AccountsRoute::Accounts),
    289         ]));
    290 
    291         if let Some(timeline) =
    292             TimelineKind::contact_list(timeline::PubkeySource::Explicit(demo_pubkey))
    293                 .into_timeline(ndb, Some(demo_pubkey.bytes()))
    294         {
    295             columns.add_new_timeline_column(timeline);
    296         }
    297 
    298         columns.add_new_timeline_column(Timeline::hashtag("introductions".to_string()));
    299 
    300         Deck {
    301             icon: '🇩',
    302             name: String::from("Demo Deck"),
    303             columns,
    304         }
    305     };
    306 
    307     Decks::new(deck)
    308 }