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 }