chiark / gitweb /
Implement the Ego Log.
authorSimon Tatham <anakin@pobox.com>
Sun, 31 Dec 2023 09:53:02 +0000 (09:53 +0000)
committerSimon Tatham <anakin@pobox.com>
Sun, 31 Dec 2023 13:05:06 +0000 (13:05 +0000)
This also meant fixing a loose end in the NotificationLog text
fragment type: it was still expecting to receive a Vec<Paragraph>,
because that's what it would have had available before we moved back
to html2text. Now it takes a single Paragraph, expecting that
Html::to_para() has sorted that out already.

src/activity_stack.rs
src/client.rs
src/file.rs
src/menu.rs
src/text.rs
src/tui.rs

index ac3b252e0fde7c49f52b0f5f3a9bf0c9f929c957..9f442239051abae6885b6aed61d1c38b3ae16b33 100644 (file)
@@ -12,6 +12,7 @@ pub enum UtilityActivity {
     ReadMentions,
     LogsMenu1,
     LogsMenu2,
+    EgoLog,
     ExitMenu,
     ExamineUser(String),
     ListUserFollowers(String),
index fbf743dec864a5c8fc72c163ba8e38a46bd1d3fa..de523db9d8433c43bb37d55f87c6073075818b44 100644 (file)
@@ -5,13 +5,13 @@ use std::io::Read;
 use super::auth::{AuthConfig,AuthError};
 use super::types::*;
 
-#[derive(Hash, PartialEq, Eq, Clone, Copy)]
+#[derive(Hash, Debug, PartialEq, Eq, Clone, Copy)]
 pub enum Boosts { Show, Hide }
 
-#[derive(Hash, PartialEq, Eq, Clone, Copy)]
+#[derive(Hash, Debug, PartialEq, Eq, Clone, Copy)]
 pub enum Replies { Show, Hide }
 
-#[derive(Hash, PartialEq, Eq, Clone)]
+#[derive(Hash, Debug, PartialEq, Eq, Clone)]
 pub enum FeedId {
     Home,
     Local,
@@ -19,6 +19,7 @@ pub enum FeedId {
     Hashtag(String),
     User(String, Boosts, Replies),
     Mentions,
+    Ego,
 }
 
 #[derive(Debug, PartialEq, Eq, Clone)]
@@ -346,6 +347,12 @@ impl Client {
             FeedId::Mentions => {
                 Req::get("notifications").param("types[]", "mention")
             },
+            FeedId::Ego => {
+                Req::get("notifications")
+                    .param("types[]", "reblog")
+                    .param("types[]", "follow")
+                    .param("types[]", "favourite")
+            },
         };
 
         let req = match ext {
@@ -385,7 +392,7 @@ impl Client {
                 }
                 sts.iter().rev().map(|st| st.id.clone()).collect()
             },
-            FeedId::Mentions => {
+            FeedId::Mentions | FeedId::Ego => {
                 let mut nots: Vec<Notification> = match serde_json::from_str(
                     &body) {
                     Ok(nots) => Ok(nots),
@@ -395,15 +402,27 @@ impl Client {
                     },
                 }?;
 
-                // According to the protocol spec, all notifications
-                // of type Mention should have a status in them. We
-                // double-check that here, so that the rest of our
-                // code can safely .unwrap() or .expect() the status
-                // from notifications they get via this feed.
-                nots.retain(|not| {
-                    not.ntype == NotificationType::Mention &&
-                        not.status.is_some()
-                });
+                match id {
+                    FeedId::Mentions => {
+                        // According to the protocol spec, all notifications
+                        // of type Mention should have a status in them. We
+                        // double-check that here, so that the rest of our
+                        // code can safely .unwrap() or .expect() the status
+                        // from notifications they get via this feed.
+                        nots.retain(|not| {
+                            not.ntype == NotificationType::Mention &&
+                                not.status.is_some()
+                        });
+                    },
+                    FeedId::Ego => {
+                        nots.retain(|not| {
+                            not.ntype == NotificationType::Reblog ||
+                                not.ntype == NotificationType::Follow ||
+                                not.ntype == NotificationType::Favourite
+                        });
+                    },
+                    _ => panic!("outer match passed us {:?}", id),
+                }
                 for not in &nots {
                     self.cache_notification(not);
                 }
@@ -512,7 +531,7 @@ impl Client {
                 // This stream interleaves updates to the home
                 // timeline with notifications, so it can cause an
                 // update in more than one thing we think of as a feed.
-                for id in &[FeedId::Home, FeedId::Mentions] {
+                for id in &[FeedId::Home, FeedId::Mentions, FeedId::Ego] {
                     if self.fetch_feed(id, FeedExtend::Future)? {
                         updates.insert(id.clone());
                     }
index 8828ea2681318658f082bbbc3b8a2f19cc2126ac..0e4460506c3e6a51bccc1392343dc7dee213cc7e 100644 (file)
@@ -48,6 +48,18 @@ impl FeedType for NotificationStatusFeedType {
     }
 }
 
+struct EgoNotificationFeedType {}
+impl FeedType for EgoNotificationFeedType {
+    type Item = NotificationLog;
+
+    fn get_from_client(id: &str, client: &mut Client) ->
+        Result<Self::Item, ClientError>
+    {
+        let not = client.notification_by_id(&id)?;
+        Ok(NotificationLog::from_notification(&not, client))
+    }
+}
+
 struct FeedFileContents<Type: FeedType> {
     id: FeedId,
     header: FileHeader,
@@ -496,3 +508,13 @@ pub fn mentions(client: &mut Client) ->
             "HHHHHHHHHHHHKKKHHKH"))?;
     Ok(Box::new(file))
 }
+
+pub fn ego_log(client: &mut Client) ->
+    Result<Box<dyn ActivityState>, ClientError>
+{
+    let file = FeedFile::<EgoNotificationFeedType>::new(
+        client, FeedId::Ego, ColouredString::general(
+            "Ego Log   [ESC][L][L][E]",
+            "HHHHHHHHHHHKKKHHKHHKHHKH"))?;
+    Ok(Box::new(file))
+}
index bcfb580a47df00cc10ee1a8785d6ce5f8f5bdc49..92774be32f7da2167f92ea333b939427d721202b 100644 (file)
@@ -266,7 +266,7 @@ pub fn logs_menu_2() -> Box<dyn ActivityState> {
             "HHHHHHHHHHHHHKKKHHKHHKH"), false);
 
     menu.add_action(Pr('E'), "Ego Log (Boosts, Follows and Faves)",
-                    LogicalAction::NYI);
+                    LogicalAction::Goto(UtilityActivity::EgoLog.into()));
 
     Box::new(menu.finalise())
 }
index 38777bd8b7623529e0fd23f186e7fe15897a42bb..a6084b73da9e8521d7e636b5faa4fad026e3620c 100644 (file)
@@ -766,12 +766,6 @@ fn test_in_reply_to() {
             });
 }
 
-pub enum NotificationLogType {
-    Favourited,
-    Boosted,
-    Followed,
-}
-
 pub struct NotificationLog {
     timestamp: DateTime<Utc>,
     account_desc: String,
@@ -781,23 +775,22 @@ pub struct NotificationLog {
 impl NotificationLog {
     pub fn new(
         timestamp: DateTime<Utc>, account: &str, nameline: &str,
-        ntype: NotificationLogType, post: Option<&Vec<Paragraph>>)
+        ntype: NotificationType, post: Option<&Paragraph>)
         -> Self {
 
         let mut para = Paragraph::new();
 
         let verb = match ntype {
-            NotificationLogType::Favourited => "favourited: ",
-            NotificationLogType::Boosted => "boosted: ",
-            NotificationLogType::Followed => "followed you",
+            NotificationType::Favourite => "favourited: ",
+            NotificationType::Reblog => "boosted: ",
+            NotificationType::Follow => "followed you",
+            _ => panic!("bad type {:?} in NotificationLog::new", ntype),
         };
         para.push_text(&ColouredString::plain(verb), false);
 
-        if let Some(paras) = post {
+        if let Some(cpara) = post {
             let currlen = para.words.len();
-            for cpara in paras {
-                para.push_para(cpara);
-            }
+            para.push_para(cpara);
             para.delete_mention_words_from(currlen);
         }
 
@@ -807,6 +800,20 @@ impl NotificationLog {
             para: para,
         }
     }
+
+    pub fn from_notification(not: &Notification, client: &mut Client) -> Self {
+        let para = match &not.status {
+            None => None,
+            Some(st) => Some(Html::new(&st.content).to_para()),
+        };
+        Self::new(
+            not.created_at,
+            &client.fq(&not.account.acct),
+            &not.account.display_name,
+            not.ntype,
+            para.as_ref(),
+        )
+    }
 }
 
 impl TextFragment for NotificationLog {
@@ -838,18 +845,14 @@ fn test_notification_log() {
                                           "%Y-%m-%d %H:%M:%S")
         .unwrap().and_local_timezone(Local).unwrap().with_timezone(&Utc);
 
-    let post = vec! {
-        Paragraph::new().add(&ColouredString::general(
-            "@stoat @weasel take a look at this otter!",
-            "@@@@@@ @@@@@@@                           ")),
-        Paragraph::new().add(&ColouredString::general(
-            "@badger might also like it",
-            "@@@@@@@                   ")),
-    };
+    let post = Paragraph::new().add(&ColouredString::general(
+        "@stoat @weasel take a look at this otter! @badger might also like it",
+        "@@@@@@ @@@@@@@                            @@@@@@@                   ",
+    ));
 
     assert_eq!(NotificationLog::new(
             t, "foo@example.com", "Foo Bar",
-            NotificationLogType::Boosted, Some(&post)).render(80), vec! {
+            NotificationType::Reblog, Some(&post)).render(80), vec! {
             ColouredString::general("Fri Aug  3 04:05:06 2001 Foo Bar (foo@example.com) boosted: take a look at this",
                                     "                                                                               "),
             ColouredString::general("  otter! @badger might also like it",
@@ -858,7 +861,7 @@ fn test_notification_log() {
 
     assert_eq!(NotificationLog::new(
             t, "foo@example.com", "Foo Bar",
-            NotificationLogType::Favourited, Some(&post)).render(51), vec! {
+            NotificationType::Favourite, Some(&post)).render(51), vec! {
             ColouredString::general("Fri Aug  3 04:05:06 2001 Foo Bar (foo@example.com)",
                                     "                                                  "),
             ColouredString::general("  favourited: take a look at this otter! @badger...",
@@ -867,7 +870,7 @@ fn test_notification_log() {
 
     assert_eq!(NotificationLog::new(
             t, "foo@example.com", "Foo Bar",
-            NotificationLogType::Followed, None).render(80), vec! {
+            NotificationType::Follow, None).render(80), vec! {
             ColouredString::general("Fri Aug  3 04:05:06 2001 Foo Bar (foo@example.com) followed you",
                                     "                                                               "),
         });
index d0754c99094dd0e204fbffc506f66577f29abf76..5fd893d15bc17ced068f1ff77fd28693486a70fc 100644 (file)
@@ -413,6 +413,8 @@ fn new_activity_state(activity: Activity, client: &mut Client) ->
             local_timeline(client),
         Activity::Util(UtilityActivity::ReadMentions) =>
             mentions(client),
+        Activity::Util(UtilityActivity::EgoLog) =>
+            ego_log(client),
         _ => panic!("FIXME"),
     };