chiark / gitweb /
Add feature to show posts by the user you're examining.
authorSimon Tatham <anakin@pobox.com>
Fri, 5 Jan 2024 06:25:53 +0000 (06:25 +0000)
committerSimon Tatham <anakin@pobox.com>
Fri, 5 Jan 2024 06:25:53 +0000 (06:25 +0000)
src/activity_stack.rs
src/file.rs
src/tui.rs

index cc08f8caa5a1a521d08ded16eb4f256848aafcdc..917ce6b88ec5610641b8476e7fb1af7c638a2ca6 100644 (file)
@@ -1,3 +1,4 @@
+use super::client::{Boosts, Replies};
 use super::file::SearchDirection;
 
 #[derive(PartialEq, Eq, Debug, Clone)]
@@ -7,6 +8,7 @@ pub enum NonUtilityActivity {
     PublicTimelineFile,
     LocalTimelineFile,
     HashtagTimeline(String),
+    UserPosts(String, Boosts, Replies),
     ComposeToplevel,
     PostComposeMenu,
 }
index 48f151494bc4f9fb99922d52435c737f51f096c4..d664605a0f71668cb060d1116430d3d512fd0c2c 100644 (file)
@@ -3,8 +3,10 @@ use regex::Regex;
 use std::cmp::{min, max};
 use std::collections::{HashMap, HashSet};
 
-use super::activity_stack::{UtilityActivity, OverlayActivity};
-use super::client::{Client, ClientError, FeedId, FeedExtend};
+use super::activity_stack::{
+    NonUtilityActivity, UtilityActivity, OverlayActivity,
+};
+use super::client::{Client, ClientError, FeedId, FeedExtend, Boosts, Replies};
 use super::coloured_string::ColouredString;
 use super::text::*;
 use super::tui::{
@@ -46,7 +48,7 @@ trait FileDataSource {
     fn extendable(&self) -> bool;
 
     fn single_id(&self) -> String {
-        panic!("Should only call this if the FileType sets CAN_LIST");
+        panic!("Should only call this if the FileType sets CAN_LIST or CAN_GET_POSTS");
     }
 }
 
@@ -115,6 +117,7 @@ enum CanList {
 trait FileType {
     type Item: TextFragment + Sized;
     const CAN_LIST: CanList = CanList::Nothing;
+    const CAN_GET_POSTS: bool = false;
 
     fn get_from_client(id: &str, client: &mut Client) ->
         Result<Self::Item, ClientError>;
@@ -275,6 +278,7 @@ enum SelectionPurpose {
 enum UIMode {
     Normal,
     ListSubmenu,
+    PostsSubmenu,
     Select(HighlightType, SelectionPurpose),
 }
 
@@ -346,7 +350,6 @@ impl<Type: FileType, Source: FileDataSource> File<Type, Source> {
             let mut lines = Vec::new();
 
             let highlight = match self.ui_mode {
-                UIMode::Normal | UIMode::ListSubmenu => None,
                 UIMode::Select(htype, _purpose) => match self.selection {
                     None => None,
                     Some((item, sub)) => if item == index {
@@ -355,6 +358,7 @@ impl<Type: FileType, Source: FileDataSource> File<Type, Source> {
                         None
                     }
                 }
+                _ => None,
             };
 
             for line in self.contents.get(index)
@@ -877,6 +881,11 @@ impl<Type: FileType, Source: FileDataSource>
                 } else {
                     fs
                 };
+                let fs = if Type::CAN_GET_POSTS {
+                    fs.add(Pr('p'), "Show Posts", 41)
+                } else {
+                    fs
+                };
                 let fs = if Type::CAN_LIST != CanList::Nothing {
                     fs.add(Pr('l'), "List", 40)
                 } else {
@@ -902,7 +911,7 @@ impl<Type: FileType, Source: FileDataSource>
                 };
                 let fs = fs
                     .add(Pr('/'), "Search Down", 20)
-                    .add(Pr('\\'), "Search Up", 19)
+                    .add(Pr('\\'), "Search Up", 20)
                     .add(Pr('q'), "Exit", 100);
 
                 // We calculate the percentage through the file in a
@@ -937,6 +946,14 @@ impl<Type: FileType, Source: FileDataSource>
                 };
                 fs.add(Pr('Q'), "Quit", 100)
             }
+            UIMode::PostsSubmenu => {
+                assert_eq!(Type::CAN_GET_POSTS, true,
+                           "How did we get here if !CAN_GET_POSTS?");
+                fs.add(Pr('A'), "All", 99)
+                    .add(Pr('O'), "Original", 97)
+                    .add(Pr('T'), "Top-level", 98)
+                    .add(Pr('Q'), "Quit", 100)
+            }
             UIMode::Select(_htype, purpose) => {
                 let fs = match purpose {
                     SelectionPurpose::ExamineUser =>
@@ -1111,6 +1128,13 @@ impl<Type: FileType, Source: FileDataSource>
                     self.search()
                 }
 
+                Pr('p') | Pr('P') => {
+                    if Type::CAN_GET_POSTS {
+                        self.ui_mode = UIMode::PostsSubmenu;
+                    }
+                    LogicalAction::Nothing
+                }
+
                 _ => LogicalAction::Nothing,
             }
             UIMode::ListSubmenu => match key {
@@ -1148,6 +1172,25 @@ impl<Type: FileType, Source: FileDataSource>
                 }
                 _ => LogicalAction::Nothing,
             }
+            UIMode::PostsSubmenu => match key {
+                Pr('a') | Pr('A') => LogicalAction::Goto(
+                    NonUtilityActivity::UserPosts(
+                        self.contents.source.single_id(),
+                        Boosts::Show, Replies::Show).into()),
+                Pr('o') | Pr('O') => LogicalAction::Goto(
+                    NonUtilityActivity::UserPosts(
+                        self.contents.source.single_id(),
+                        Boosts::Hide, Replies::Show).into()),
+                Pr('t') | Pr('T') => LogicalAction::Goto(
+                    NonUtilityActivity::UserPosts(
+                        self.contents.source.single_id(),
+                        Boosts::Hide, Replies::Hide).into()),
+                Pr('q') | Pr('Q') => {
+                    self.ui_mode = UIMode::Normal;
+                    LogicalAction::Nothing
+                }
+                _ => LogicalAction::Nothing,
+            }
             UIMode::Select(_, purpose) => match key {
                 Space => self.complete_selection(client, false),
                 Pr('d') | Pr('D') => match purpose {
@@ -1272,6 +1315,21 @@ pub fn ego_log(file_positions: &HashMap<FeedId, FilePosition>,
     Ok(Box::new(file))
 }
 
+pub fn user_posts(
+    file_positions: &HashMap<FeedId, FilePosition>, client: &mut Client,
+    user: &str, boosts: Boosts, replies: Replies)
+    -> Result<Box<dyn ActivityState>, ClientError>
+{
+    let feed = FeedId::User(user.to_owned(), boosts, replies);
+    let pos = file_positions.get(&feed).cloned();
+    let desc = StatusFeedType::with_feed(feed.clone());
+    let file = File::new(
+        client, FeedSource::new(feed), ColouredString::general(
+            "Public timeline   <P>",
+            "HHHHHHHHHHHHHHHHHHHKH"), desc, pos)?;
+    Ok(Box::new(file))
+}
+
 pub fn list_status_favouriters(client: &mut Client, id: &str) ->
     Result<Box<dyn ActivityState>, ClientError>
 {
@@ -1339,6 +1397,7 @@ struct ExamineUserFileType {}
 impl FileType for ExamineUserFileType {
     type Item = ExamineUserDisplay;
     const CAN_LIST: CanList = CanList::ForUser;
+    const CAN_GET_POSTS: bool = true;
 
     fn get_from_client(id: &str, client: &mut Client) ->
         Result<Self::Item, ClientError>
index fd3b535f15dfdbb3c3e39d8d9e48c577b15ee081..70e1288bc0a932566ab55e6b0bad65eff6bb06b8 100644 (file)
@@ -702,6 +702,9 @@ fn new_activity_state(&self, activity: Activity, client: &mut Client,
                 list_user_followers(client, id),
             Activity::Util(UtilityActivity::ListUserFollowees(ref id)) =>
                 list_user_followees(client, id),
+            Activity::NonUtil(NonUtilityActivity::UserPosts(
+                ref user, boosts, replies)) =>
+                user_posts(&self.file_positions, client, user, boosts, replies),
         };
 
         result.expect("FIXME: need to implement the Error Log here")