From 8244bd94c916d52df85a70bd1e7c2550e50ed619 Mon Sep 17 00:00:00 2001 From: Bendt Date: Thu, 18 Dec 2025 13:29:56 -0500 Subject: [PATCH] bug fix display and load --- .coverage | Bin 69632 -> 69632 bytes src/maildir_gtd/actions/delete.py | 6 ++-- src/maildir_gtd/app.py | 21 ++++++++++++++ src/maildir_gtd/config.py | 8 ++++++ src/maildir_gtd/email_viewer.tcss | 11 +++++++ src/maildir_gtd/widgets/EnvelopeListItem.py | 3 ++ src/services/himalaya/client.py | 30 ++++++++++++++------ 7 files changed, 68 insertions(+), 11 deletions(-) diff --git a/.coverage b/.coverage index c1201d523f8e13c22e0cc29a52d1c74b41378623..0aee14dbce7f2ed678e0cf1f18dd55f0d7865fc9 100644 GIT binary patch delta 280 zcmZozz|ydQWdmCSqyJ>~1_k$8-UMC`UQM3cJX3f&c^Y}*dHi`acocXfcm%kAa3AE} z!9A6`m%EAEpIeXXEZ1VLSzOIrRb1{|l3a|OS2)jbZsT0WS;6VQSy131$L6q3Hzs98 zMHWU*7m0l=3=9lR3=9eo3P>_A0x?LGWAfha0(Dg>pgJF=Td55|ArNq2XAl5VKouMy zE(;Tb4g(|8=HMPdMips6pkfQrs?&0l)sNWx{(nBjD6;H60~^qI4~HlLRz}W7lgaJ9 zO2#0)2|(R!3=9%L3g`eP1_2gE4n__Kkl|pU;^^YS;sBIl5O7iH6xe*TSG@@UZxS}6 delta 273 zcmZozz|ydQWdmCSW7uT&1_k#9-V|ORUR|F1JTrKDd0Kgrd4hR#c~p61c|^JYav$T~ z%RPsC3U?=W7`G|c6|PlW3%R= len(self.message_store.envelopes): + return + current_item = self.message_store.envelopes[selected_index] if current_item is None or current_item.get("type") == "header": @@ -261,13 +269,26 @@ class EmailViewerApp(App): self.current_message_id = message_id self.current_message_index = selected_index + # Focus the main content panel after selecting a message + self.action_focus_4() + def on_list_view_highlighted(self, event: ListView.Highlighted) -> None: """Called when an item in the list view is highlighted (e.g., via arrow keys).""" if event.list_view.index is None: return + # Only handle highlights from the envelopes list + if event.list_view.id != "envelopes_list": + return + highlighted_index = event.list_view.index + # Check bounds before accessing + if highlighted_index < 0 or highlighted_index >= len( + self.message_store.envelopes + ): + return + current_item = self.message_store.envelopes[highlighted_index] if current_item is None or current_item.get("type") == "header": diff --git a/src/maildir_gtd/config.py b/src/maildir_gtd/config.py index 8b67190..3d949b7 100644 --- a/src/maildir_gtd/config.py +++ b/src/maildir_gtd/config.py @@ -89,6 +89,13 @@ class LinkPanelConfig(BaseModel): close_on_open: bool = False +class MailConfig(BaseModel): + """Configuration for mail operations.""" + + # Folder to move messages to when archiving + archive_folder: str = "Archive" + + class ThemeConfig(BaseModel): """Theme/appearance settings.""" @@ -104,6 +111,7 @@ class MaildirGTDConfig(BaseModel): ) content_display: ContentDisplayConfig = Field(default_factory=ContentDisplayConfig) link_panel: LinkPanelConfig = Field(default_factory=LinkPanelConfig) + mail: MailConfig = Field(default_factory=MailConfig) keybindings: KeybindingsConfig = Field(default_factory=KeybindingsConfig) theme: ThemeConfig = Field(default_factory=ThemeConfig) diff --git a/src/maildir_gtd/email_viewer.tcss b/src/maildir_gtd/email_viewer.tcss index a3962c5..a6b58f8 100644 --- a/src/maildir_gtd/email_viewer.tcss +++ b/src/maildir_gtd/email_viewer.tcss @@ -11,17 +11,23 @@ width: 1fr } +.list_view { + height: 3; +} + #main_content { width: 2fr; } + .envelope-selected { tint: $accent 20%; } #sidebar:focus-within { background: $panel; + .list_view:blur { height: 3; } @@ -30,6 +36,11 @@ } } + +#envelopes_list { + height: 2fr; +} + #main_content:focus, .list_view:focus { border: round $secondary; background: rgb(55, 53, 57); diff --git a/src/maildir_gtd/widgets/EnvelopeListItem.py b/src/maildir_gtd/widgets/EnvelopeListItem.py index ba775ae..45118f4 100644 --- a/src/maildir_gtd/widgets/EnvelopeListItem.py +++ b/src/maildir_gtd/widgets/EnvelopeListItem.py @@ -147,6 +147,9 @@ class EnvelopeListItem(Static): date_str = date_str.replace("Z", "+00:00") dt = datetime.fromisoformat(date_str) + # Convert to local timezone + dt = dt.astimezone() + parts = [] if self.config.show_date: parts.append(dt.strftime(self.config.date_format)) diff --git a/src/services/himalaya/client.py b/src/services/himalaya/client.py index 2769eb6..8195742 100644 --- a/src/services/himalaya/client.py +++ b/src/services/himalaya/client.py @@ -4,6 +4,8 @@ import json import logging import subprocess +from src.maildir_gtd.config import get_config + async def list_envelopes(limit: int = 9999) -> Tuple[List[Dict[str, Any]], bool]: """ @@ -92,7 +94,7 @@ async def list_folders() -> Tuple[List[Dict[str, Any]], bool]: return [], False -async def delete_message(message_id: int) -> bool: +async def delete_message(message_id: int) -> Tuple[Optional[str], bool]: """ Delete a message by its ID. @@ -100,7 +102,9 @@ async def delete_message(message_id: int) -> bool: message_id: The ID of the message to delete Returns: - True if deletion was successful, False otherwise + Tuple containing: + - Result message or error + - Success status (True if deletion was successful) """ try: process = await asyncio.create_subprocess_shell( @@ -110,10 +114,15 @@ async def delete_message(message_id: int) -> bool: ) stdout, stderr = await process.communicate() - return process.returncode == 0 + if process.returncode == 0: + return stdout.decode().strip() or "Deleted successfully", True + else: + error_msg = stderr.decode().strip() + logging.error(f"Error deleting message: {error_msg}") + return error_msg or "Unknown error", False except Exception as e: logging.error(f"Exception during message deletion: {e}") - return False + return str(e), False # async def archive_message(message_id: int) -> [str, bool]: @@ -151,8 +160,10 @@ async def archive_messages(message_ids: List[str]) -> Tuple[Optional[str], bool] A tuple containing an optional output string and a boolean indicating success. """ try: + config = get_config() + archive_folder = config.mail.archive_folder ids_str = " ".join(message_ids) - cmd = f"himalaya message move Archives {ids_str}" + cmd = f"himalaya message move {archive_folder} {ids_str}" process = await asyncio.create_subprocess_shell( cmd, @@ -162,13 +173,14 @@ async def archive_messages(message_ids: List[str]) -> Tuple[Optional[str], bool] stdout, stderr = await process.communicate() if process.returncode == 0: - return stdout.decode(), True + return stdout.decode().strip() or "Archived successfully", True else: - logging.error(f"Error archiving messages: {stderr.decode()}") - return None, False + error_msg = stderr.decode().strip() + logging.error(f"Error archiving messages: {error_msg}") + return error_msg or "Unknown error", False except Exception as e: logging.error(f"Exception during message archiving: {e}") - return None, False + return str(e), False async def get_message_content(message_id: int) -> Tuple[Optional[str], bool]: