From b3c37ae625246ae992026081e31f19ec18dda6e3 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Thu, 24 Jul 2025 02:05:04 -0400 Subject: [PATCH] Implement seamless auto-loading timeline navigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove explicit "Load more posts" items from timeline view - Auto-load more posts when down arrow pressed at timeline end - Create seamless infinite-scroll experience for better UX - Maintain focus on newly loaded content for smooth navigation - Reduce status message display time to 1 second for less interruption - Update accessibility name to "Timeline Tree" for consistency This creates a more natural browsing experience where users can continuously navigate through their timeline without manual loading prompts. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/widgets/timeline_view.py | 77 +++++++++++++++--------------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/src/widgets/timeline_view.py b/src/widgets/timeline_view.py index cb9622a..55fd2a4 100644 --- a/src/widgets/timeline_view.py +++ b/src/widgets/timeline_view.py @@ -116,7 +116,7 @@ class TimelineView(QTreeWidget): self.setFocusPolicy(Qt.StrongFocus) # Set accessible properties - self.setAccessibleName("Timeline") + self.setAccessibleName("Timeline Tree") self.setAccessibleDescription("Timeline showing posts and conversations") def set_timeline_type(self, timeline_type: str): @@ -1151,13 +1151,10 @@ class TimelineView(QTreeWidget): ) def add_load_more_item(self): - """Add a 'Load more posts' item at the bottom of the timeline""" - load_more_item = QTreeWidgetItem(["Load more posts (Press Enter)"]) - load_more_item.setData(0, Qt.UserRole, "load_more") # Special marker - load_more_item.setData( - 0, Qt.AccessibleTextRole, "Load more posts from timeline" - ) - self.addTopLevelItem(load_more_item) + """Legacy method - no longer adds visible 'Load more posts' item""" + # Auto-loading on down arrow makes explicit load more items unnecessary + # Keep method for compatibility but don't add any visible items + pass def load_more_posts(self): """Load more posts from the current timeline""" @@ -1200,11 +1197,8 @@ class TimelineView(QTreeWidget): ) if more_data: - # Remember current "Load more" item position - load_more_index = self.get_load_more_item_index() - - # Remove current "Load more" item - self.remove_load_more_item() + # Get current position to add new posts + insert_index = self.topLevelItemCount() # Add new posts to existing list self.load_additional_timeline_data(more_data) @@ -1213,24 +1207,18 @@ class TimelineView(QTreeWidget): self.oldest_post_id = more_data[-1]["id"] # Add new posts to the tree without rebuilding everything - self.add_new_posts_to_tree(more_data, load_more_index) + self.add_new_posts_to_tree(more_data, insert_index) - # Add new "Load more" item at the end - self.add_load_more_item() - - # Focus on the first newly added post so user can arrow down to read them - if ( - load_more_index is not None - and load_more_index < self.topLevelItemCount() - ): - first_new_item = self.topLevelItem(load_more_index) + # Focus on the first newly added post so user can continue reading + if insert_index < self.topLevelItemCount(): + first_new_item = self.topLevelItem(insert_index) if first_new_item: self.setCurrentItem(first_new_item) self.scrollToItem(first_new_item) if hasattr(self, "parent") and hasattr(self.parent(), "status_bar"): self.parent().status_bar.showMessage( - f"Loaded {len(more_data)} more posts", 2000 + f"Loaded {len(more_data)} more posts", 1000 ) else: if hasattr(self, "parent") and hasattr(self.parent(), "status_bar"): @@ -1244,20 +1232,12 @@ class TimelineView(QTreeWidget): ) def get_load_more_item_index(self): - """Get the index of the 'Load more posts' item""" - for i in range(self.topLevelItemCount()): - item = self.topLevelItem(i) - if item.data(0, Qt.UserRole) == "load_more": - return i + """Legacy method - no longer needed as there are no load more items""" return None def remove_load_more_item(self): - """Remove the 'Load more posts' item""" - for i in range(self.topLevelItemCount()): - item = self.topLevelItem(i) - if item.data(0, Qt.UserRole) == "load_more": - self.takeTopLevelItem(i) - break + """Legacy method - no longer needed as there are no load more items""" + pass def load_additional_timeline_data(self, timeline_data): """Load additional timeline data and append to existing posts""" @@ -1371,7 +1351,7 @@ class TimelineView(QTreeWidget): return post = item.data(0, Qt.UserRole) - if not post or post == "load_more": + if not post: return menu = QMenu(self) @@ -1632,7 +1612,7 @@ class TimelineView(QTreeWidget): self.logger.error(f"Error updating conversation display: {e}") def keyPressEvent(self, event: QKeyEvent): - """Handle keyboard events, including Enter for poll voting and context menu keys""" + """Handle keyboard events, including Enter for poll voting and automatic loading""" key = event.key() current = self.currentItem() @@ -1648,15 +1628,22 @@ class TimelineView(QTreeWidget): self.customContextMenuRequested.emit(center) return - # Handle Enter key for polls, load more, and post details - if (key == Qt.Key_Return or key == Qt.Key_Enter) and current: - # Check for special items first - special_data = current.data(0, Qt.UserRole) - if special_data == "load_more": - self.load_more_posts() - return + # Handle down arrow at end of timeline - automatically load more posts + if key == Qt.Key_Down and current: + # Check if we're at the last post in the timeline + current_index = self.indexOfTopLevelItem(current) + total_items = self.topLevelItemCount() + + # If we're at the last post, automatically load more + if current_index >= total_items - 1: + # Only auto-load if we actually have an API client and more data might be available + if self.activitypub_client and self.oldest_post_id: + self.load_more_posts() + return - # Check if current item has poll data + # Handle Enter key for post details + if (key == Qt.Key_Return or key == Qt.Key_Enter) and current: + # Check if current item has post data try: post_index = self.indexOfTopLevelItem(current) if 0 <= post_index < len(self.posts):