notedeck

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

route.rs (7026B)


      1 use enostr::{NoteId, Pubkey};
      2 use std::fmt::{self};
      3 
      4 use crate::{
      5     accounts::AccountsRoute,
      6     column::Columns,
      7     timeline::{kind::ColumnTitle, TimelineId, TimelineRoute},
      8     ui::add_column::AddColumnRoute,
      9 };
     10 
     11 /// App routing. These describe different places you can go inside Notedeck.
     12 #[derive(Clone, Copy, Eq, PartialEq, Debug)]
     13 pub enum Route {
     14     Timeline(TimelineRoute),
     15     Accounts(AccountsRoute),
     16     Relays,
     17     ComposeNote,
     18     AddColumn(AddColumnRoute),
     19     EditProfile(Pubkey),
     20     Support,
     21     NewDeck,
     22     EditDeck(usize),
     23 }
     24 
     25 impl Route {
     26     pub fn timeline(timeline_id: TimelineId) -> Self {
     27         Route::Timeline(TimelineRoute::Timeline(timeline_id))
     28     }
     29 
     30     pub fn timeline_id(&self) -> Option<&TimelineId> {
     31         if let Route::Timeline(TimelineRoute::Timeline(tid)) = self {
     32             Some(tid)
     33         } else {
     34             None
     35         }
     36     }
     37 
     38     pub fn relays() -> Self {
     39         Route::Relays
     40     }
     41 
     42     pub fn thread(thread_root: NoteId) -> Self {
     43         Route::Timeline(TimelineRoute::Thread(thread_root))
     44     }
     45 
     46     pub fn profile(pubkey: Pubkey) -> Self {
     47         Route::Timeline(TimelineRoute::Profile(pubkey))
     48     }
     49 
     50     pub fn reply(replying_to: NoteId) -> Self {
     51         Route::Timeline(TimelineRoute::Reply(replying_to))
     52     }
     53 
     54     pub fn quote(quoting: NoteId) -> Self {
     55         Route::Timeline(TimelineRoute::Quote(quoting))
     56     }
     57 
     58     pub fn accounts() -> Self {
     59         Route::Accounts(AccountsRoute::Accounts)
     60     }
     61 
     62     pub fn add_account() -> Self {
     63         Route::Accounts(AccountsRoute::AddAccount)
     64     }
     65 
     66     pub fn title<'a>(&self, columns: &'a Columns) -> ColumnTitle<'a> {
     67         match self {
     68             Route::Timeline(tlr) => match tlr {
     69                 TimelineRoute::Timeline(id) => {
     70                     if let Some(timeline) = columns.find_timeline(*id) {
     71                         timeline.kind.to_title()
     72                     } else {
     73                         ColumnTitle::simple("Unknown")
     74                     }
     75                 }
     76                 TimelineRoute::Thread(_id) => ColumnTitle::simple("Thread"),
     77                 TimelineRoute::Reply(_id) => ColumnTitle::simple("Reply"),
     78                 TimelineRoute::Quote(_id) => ColumnTitle::simple("Quote"),
     79                 TimelineRoute::Profile(_pubkey) => ColumnTitle::simple("Profile"),
     80             },
     81 
     82             Route::Relays => ColumnTitle::simple("Relays"),
     83 
     84             Route::Accounts(amr) => match amr {
     85                 AccountsRoute::Accounts => ColumnTitle::simple("Accounts"),
     86                 AccountsRoute::AddAccount => ColumnTitle::simple("Add Account"),
     87             },
     88             Route::ComposeNote => ColumnTitle::simple("Compose Note"),
     89             Route::AddColumn(c) => match c {
     90                 AddColumnRoute::Base => ColumnTitle::simple("Add Column"),
     91                 AddColumnRoute::UndecidedNotification => {
     92                     ColumnTitle::simple("Add Notifications Column")
     93                 }
     94                 AddColumnRoute::ExternalNotification => {
     95                     ColumnTitle::simple("Add External Notifications Column")
     96                 }
     97                 AddColumnRoute::Hashtag => ColumnTitle::simple("Add Hashtag Column"),
     98                 AddColumnRoute::UndecidedIndividual => {
     99                     ColumnTitle::simple("Subscribe to someone's notes")
    100                 }
    101                 AddColumnRoute::ExternalIndividual => {
    102                     ColumnTitle::simple("Subscribe to someone else's notes")
    103                 }
    104             },
    105             Route::Support => ColumnTitle::simple("Damus Support"),
    106             Route::NewDeck => ColumnTitle::simple("Add Deck"),
    107             Route::EditDeck(_) => ColumnTitle::simple("Edit Deck"),
    108             Route::EditProfile(_) => ColumnTitle::simple("Edit Profile"),
    109         }
    110     }
    111 }
    112 
    113 // TODO: add this to egui-nav so we don't have to deal with returning
    114 // and navigating headaches
    115 #[derive(Clone)]
    116 pub struct Router<R: Clone> {
    117     routes: Vec<R>,
    118     pub returning: bool,
    119     pub navigating: bool,
    120     replacing: bool,
    121 }
    122 
    123 impl<R: Clone> Router<R> {
    124     pub fn new(routes: Vec<R>) -> Self {
    125         if routes.is_empty() {
    126             panic!("routes can't be empty")
    127         }
    128         let returning = false;
    129         let navigating = false;
    130         let replacing = false;
    131         Router {
    132             routes,
    133             returning,
    134             navigating,
    135             replacing,
    136         }
    137     }
    138 
    139     pub fn route_to(&mut self, route: R) {
    140         self.navigating = true;
    141         self.routes.push(route);
    142     }
    143 
    144     // Route to R. Then when it is successfully placed, should call `remove_previous_routes` to remove all previous routes
    145     pub fn route_to_replaced(&mut self, route: R) {
    146         self.navigating = true;
    147         self.replacing = true;
    148         self.routes.push(route);
    149     }
    150 
    151     /// Go back, start the returning process
    152     pub fn go_back(&mut self) -> Option<R> {
    153         if self.returning || self.routes.len() == 1 {
    154             return None;
    155         }
    156         self.returning = true;
    157         self.prev().cloned()
    158     }
    159 
    160     /// Pop a route, should only be called on a NavRespose::Returned reseponse
    161     pub fn pop(&mut self) -> Option<R> {
    162         if self.routes.len() == 1 {
    163             return None;
    164         }
    165         self.returning = false;
    166         self.routes.pop()
    167     }
    168 
    169     pub fn remove_previous_routes(&mut self) {
    170         let num_routes = self.routes.len();
    171         if num_routes <= 1 {
    172             return;
    173         }
    174 
    175         self.returning = false;
    176         self.replacing = false;
    177         self.routes.drain(..num_routes - 1);
    178     }
    179 
    180     pub fn is_replacing(&self) -> bool {
    181         self.replacing
    182     }
    183 
    184     pub fn top(&self) -> &R {
    185         self.routes.last().expect("routes can't be empty")
    186     }
    187 
    188     pub fn prev(&self) -> Option<&R> {
    189         self.routes.get(self.routes.len() - 2)
    190     }
    191 
    192     pub fn routes(&self) -> &Vec<R> {
    193         &self.routes
    194     }
    195 }
    196 
    197 impl fmt::Display for Route {
    198     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    199         match self {
    200             Route::Timeline(tlr) => match tlr {
    201                 TimelineRoute::Timeline(name) => write!(f, "{}", name),
    202                 TimelineRoute::Thread(_id) => write!(f, "Thread"),
    203                 TimelineRoute::Profile(_id) => write!(f, "Profile"),
    204                 TimelineRoute::Reply(_id) => write!(f, "Reply"),
    205                 TimelineRoute::Quote(_id) => write!(f, "Quote"),
    206             },
    207 
    208             Route::Relays => write!(f, "Relays"),
    209 
    210             Route::Accounts(amr) => match amr {
    211                 AccountsRoute::Accounts => write!(f, "Accounts"),
    212                 AccountsRoute::AddAccount => write!(f, "Add Account"),
    213             },
    214             Route::ComposeNote => write!(f, "Compose Note"),
    215 
    216             Route::AddColumn(_) => write!(f, "Add Column"),
    217             Route::Support => write!(f, "Support"),
    218             Route::NewDeck => write!(f, "Add Deck"),
    219             Route::EditDeck(_) => write!(f, "Edit Deck"),
    220             Route::EditProfile(_) => write!(f, "Edit Profile"),
    221         }
    222     }
    223 }