notedeck

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

column.rs (4646B)


      1 use crate::error::FilterError;
      2 use crate::filter;
      3 use crate::filter::FilterState;
      4 use crate::{timeline::Timeline, Error};
      5 use enostr::Pubkey;
      6 use nostrdb::{Filter, Ndb, Transaction};
      7 use std::fmt::Display;
      8 use tracing::{error, warn};
      9 
     10 #[derive(Clone, Debug)]
     11 pub enum PubkeySource {
     12     Explicit(Pubkey),
     13     DeckAuthor,
     14 }
     15 
     16 #[derive(Debug, Clone)]
     17 pub enum ListKind {
     18     Contact(PubkeySource),
     19 }
     20 
     21 ///
     22 /// What kind of column is it?
     23 ///   - Follow List
     24 ///   - Notifications
     25 ///   - DM
     26 ///   - filter
     27 ///   - ... etc
     28 #[derive(Debug, Clone)]
     29 pub enum ColumnKind {
     30     List(ListKind),
     31 
     32     Notifications(PubkeySource),
     33 
     34     Profile(PubkeySource),
     35 
     36     Universe,
     37 
     38     /// Generic filter
     39     Generic,
     40 }
     41 
     42 impl Display for ColumnKind {
     43     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     44         match self {
     45             ColumnKind::List(ListKind::Contact(_src)) => f.write_str("Contacts"),
     46             ColumnKind::Generic => f.write_str("Timeline"),
     47             ColumnKind::Notifications(_) => f.write_str("Notifications"),
     48             ColumnKind::Profile(_) => f.write_str("Profile"),
     49             ColumnKind::Universe => f.write_str("Universe"),
     50         }
     51     }
     52 }
     53 
     54 impl ColumnKind {
     55     pub fn contact_list(pk: PubkeySource) -> Self {
     56         ColumnKind::List(ListKind::Contact(pk))
     57     }
     58 
     59     pub fn profile(pk: PubkeySource) -> Self {
     60         ColumnKind::Profile(pk)
     61     }
     62 
     63     pub fn notifications(pk: PubkeySource) -> Self {
     64         ColumnKind::Notifications(pk)
     65     }
     66 
     67     pub fn into_timeline(self, ndb: &Ndb, default_user: Option<&[u8; 32]>) -> Option<Timeline> {
     68         match self {
     69             ColumnKind::Universe => Some(Timeline::new(
     70                 ColumnKind::Universe,
     71                 FilterState::ready(vec![Filter::new()
     72                     .kinds([1])
     73                     .limit(filter::default_limit())
     74                     .build()]),
     75             )),
     76 
     77             ColumnKind::Generic => {
     78                 warn!("you can't convert a ColumnKind::Generic to a Timeline");
     79                 None
     80             }
     81 
     82             ColumnKind::Profile(pk_src) => {
     83                 let pk = match &pk_src {
     84                     PubkeySource::DeckAuthor => default_user?,
     85                     PubkeySource::Explicit(pk) => pk.bytes(),
     86                 };
     87 
     88                 let filter = Filter::new()
     89                     .authors([pk])
     90                     .kinds([1])
     91                     .limit(filter::default_limit())
     92                     .build();
     93 
     94                 Some(Timeline::new(
     95                     ColumnKind::profile(pk_src),
     96                     FilterState::ready(vec![filter]),
     97                 ))
     98             }
     99 
    100             ColumnKind::Notifications(pk_src) => {
    101                 let pk = match &pk_src {
    102                     PubkeySource::DeckAuthor => default_user?,
    103                     PubkeySource::Explicit(pk) => pk.bytes(),
    104                 };
    105 
    106                 let notifications_filter = Filter::new()
    107                     .pubkeys([pk])
    108                     .kinds([1])
    109                     .limit(filter::default_limit())
    110                     .build();
    111 
    112                 Some(Timeline::new(
    113                     ColumnKind::notifications(pk_src),
    114                     FilterState::ready(vec![notifications_filter]),
    115                 ))
    116             }
    117 
    118             ColumnKind::List(ListKind::Contact(pk_src)) => {
    119                 let pk = match &pk_src {
    120                     PubkeySource::DeckAuthor => default_user?,
    121                     PubkeySource::Explicit(pk) => pk.bytes(),
    122                 };
    123 
    124                 let contact_filter = Filter::new().authors([pk]).kinds([3]).limit(1).build();
    125 
    126                 let txn = Transaction::new(ndb).expect("txn");
    127                 let results = ndb
    128                     .query(&txn, &[contact_filter.clone()], 1)
    129                     .expect("contact query failed?");
    130 
    131                 if results.is_empty() {
    132                     return Some(Timeline::new(
    133                         ColumnKind::contact_list(pk_src),
    134                         FilterState::needs_remote(vec![contact_filter.clone()]),
    135                     ));
    136                 }
    137 
    138                 match Timeline::contact_list(&results[0].note) {
    139                     Err(Error::Filter(FilterError::EmptyContactList)) => Some(Timeline::new(
    140                         ColumnKind::contact_list(pk_src),
    141                         FilterState::needs_remote(vec![contact_filter]),
    142                     )),
    143                     Err(e) => {
    144                         error!("Unexpected error: {e}");
    145                         None
    146                     }
    147                     Ok(tl) => Some(tl),
    148                 }
    149             }
    150         }
    151     }
    152 }