From: Simon Tatham Date: Sun, 31 Dec 2023 09:53:02 +0000 (+0000) Subject: Implement the Ego Log. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=ca190da1a7f954fa799f1e96e39b7dd4c4bb147a;p=mastodonochrome.git Implement the Ego Log. This also meant fixing a loose end in the NotificationLog text fragment type: it was still expecting to receive a Vec, 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. --- diff --git a/src/activity_stack.rs b/src/activity_stack.rs index ac3b252..9f44223 100644 --- a/src/activity_stack.rs +++ b/src/activity_stack.rs @@ -12,6 +12,7 @@ pub enum UtilityActivity { ReadMentions, LogsMenu1, LogsMenu2, + EgoLog, ExitMenu, ExamineUser(String), ListUserFollowers(String), diff --git a/src/client.rs b/src/client.rs index fbf743d..de523db 100644 --- a/src/client.rs +++ b/src/client.rs @@ -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 = 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 ¬s { 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()); } diff --git a/src/file.rs b/src/file.rs index 8828ea2..0e44605 100644 --- a/src/file.rs +++ b/src/file.rs @@ -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 + { + let not = client.notification_by_id(&id)?; + Ok(NotificationLog::from_notification(¬, client)) + } +} + struct FeedFileContents { 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, ClientError> +{ + let file = FeedFile::::new( + client, FeedId::Ego, ColouredString::general( + "Ego Log [ESC][L][L][E]", + "HHHHHHHHHHHKKKHHKHHKHHKH"))?; + Ok(Box::new(file)) +} diff --git a/src/menu.rs b/src/menu.rs index bcfb580..92774be 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -266,7 +266,7 @@ pub fn logs_menu_2() -> Box { "HHHHHHHHHHHHHKKKHHKHHKH"), false); menu.add_action(Pr('E'), "Ego Log (Boosts, Follows and Faves)", - LogicalAction::NYI); + LogicalAction::Goto(UtilityActivity::EgoLog.into())); Box::new(menu.finalise()) } diff --git a/src/text.rs b/src/text.rs index 38777bd..a6084b7 100644 --- a/src/text.rs +++ b/src/text.rs @@ -766,12 +766,6 @@ fn test_in_reply_to() { }); } -pub enum NotificationLogType { - Favourited, - Boosted, - Followed, -} - pub struct NotificationLog { timestamp: DateTime, account_desc: String, @@ -781,23 +775,22 @@ pub struct NotificationLog { impl NotificationLog { pub fn new( timestamp: DateTime, account: &str, nameline: &str, - ntype: NotificationLogType, post: Option<&Vec>) + 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 ¬.status { + None => None, + Some(st) => Some(Html::new(&st.content).to_para()), + }; + Self::new( + not.created_at, + &client.fq(¬.account.acct), + ¬.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", " "), }); diff --git a/src/tui.rs b/src/tui.rs index d0754c9..5fd893d 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -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"), };