From daca679fb99e258dea04b473639924bc1ca06fcb Mon Sep 17 00:00:00 2001 From: Hunter Jozwiak Date: Sun, 20 Jul 2025 20:43:32 -0400 Subject: [PATCH] Fix username autocomplete for Pleroma instances and remote users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enhanced API search limits from 10 to 40 users with remote resolution - Added 'resolve: True' parameter to enable finding users from remote instances - Improved filtering logic to match username parts before @ symbol - Increased follower/following search limits from 50 to 100 each - Added Pleroma compatibility with parameter validation and fallback endpoints - Fixed state management for autocomplete re-triggering after API calls - Now successfully finds remote users like storm@social.wolfe.casa 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/activitypub/client.py | 24 +++++++++++++++++++++--- src/widgets/autocomplete_textedit.py | 26 ++++++++++++++++++++++---- src/widgets/compose_dialog.py | 6 +++--- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/activitypub/client.py b/src/activitypub/client.py index 0f897e5..89d436e 100644 --- a/src/activitypub/client.py +++ b/src/activitypub/client.py @@ -198,14 +198,32 @@ class ActivityPubClient: def search_accounts(self, query: str, limit: int = 10) -> List[Dict]: """Search for accounts by username""" + # Ensure limit is a valid integer for Pleroma compatibility + limit = max(1, min(int(limit), 80)) + params = { 'q': query, 'type': 'accounts', - 'limit': limit + 'limit': limit, + 'resolve': True # Enable remote user resolution } - result = self._make_request('GET', '/api/v2/search', params=params) - return result.get('accounts', []) + try: + # Try v2 search first (preferred) + result = self._make_request('GET', '/api/v2/search', params=params) + return result.get('accounts', []) + except Exception: + try: + # Fallback to v1 accounts search (Pleroma-friendly) + fallback_params = { + 'q': query, + 'limit': limit, + 'resolve': True + } + return self._make_request('GET', '/api/v1/accounts/search', params=fallback_params) + except Exception: + # Return empty list if both fail + return [] def search(self, query: str, account_id: Optional[str] = None, max_id: Optional[str] = None, min_id: Optional[str] = None, diff --git a/src/widgets/autocomplete_textedit.py b/src/widgets/autocomplete_textedit.py index 733ca96..ea5c01c 100644 --- a/src/widgets/autocomplete_textedit.py +++ b/src/widgets/autocomplete_textedit.py @@ -178,13 +178,29 @@ class AutocompleteTextEdit(QTextEdit): def show_mention_completer(self, prefix: str, start_pos: int): """Show mention autocomplete""" + if not self.mention_list: + # Save completion state for when data arrives + self.completion_prefix = prefix + self.completion_start = start_pos + self.completion_type = 'mention' # Request mention list from parent self.mention_requested.emit(prefix) return - # Filter mentions - matches = [name for name in self.mention_list if name.lower().startswith(prefix.lower())] + # Filter mentions - check if prefix matches username part or full handle + matches = [] + prefix_lower = prefix.lower() + for name in self.mention_list: + name_lower = name.lower() + # Check if prefix matches the beginning of the username (before @) + username_part = name_lower.split('@')[0] if '@' in name_lower else name_lower + match_username = username_part.startswith(prefix_lower) + match_full = name_lower.startswith(prefix_lower) + if match_username or match_full: + matches.append(name) + else: + if matches: self.show_completer(matches, prefix, start_pos, 'mention') @@ -311,5 +327,7 @@ class AutocompleteTextEdit(QTextEdit): def update_mention_list(self, mentions: List[str]): """Update mention list (called from parent when data is ready)""" self.mention_list = mentions - # Don't re-trigger completer to avoid recursion - # The completer will use the updated list on next keystroke \ No newline at end of file + + # If we were waiting for mention data, re-trigger the completer + if self.completion_type == 'mention' and self.completion_prefix: + self.show_mention_completer(self.completion_prefix, self.completion_start) \ No newline at end of file diff --git a/src/widgets/compose_dialog.py b/src/widgets/compose_dialog.py index bc584d2..07efc53 100644 --- a/src/widgets/compose_dialog.py +++ b/src/widgets/compose_dialog.py @@ -242,7 +242,7 @@ class ComposeDialog(QDialog): # 1. Search for accounts matching the prefix if len(prefix) >= 1: # Search when user has typed at least 1 character try: - search_results = client.search_accounts(prefix, limit=10) + search_results = client.search_accounts(prefix, limit=40) for account in search_results: # Use full fediverse handle (acct field) or construct it full_handle = account.get('acct', '') @@ -261,7 +261,7 @@ class ComposeDialog(QDialog): # 2. Get followers (people who follow you) try: - followers = client.get_followers(current_account_id, limit=50) + followers = client.get_followers(current_account_id, limit=100) for follower in followers: # Use full fediverse handle full_handle = follower.get('acct', '') @@ -280,7 +280,7 @@ class ComposeDialog(QDialog): # 3. Get following (people you follow) try: - following = client.get_following(current_account_id, limit=50) + following = client.get_following(current_account_id, limit=100) for account in following: # Use full fediverse handle full_handle = account.get('acct', '')